home *** CD-ROM | disk | FTP | other *** search
/ Software of the Month Club 1996 June / Software of the Month Club 1996 June.iso / pc / os2 / utility / clock / clock.cpp < prev    next >
C/C++ Source or Header  |  1996-02-21  |  113KB  |  3,012 lines

  1. /****************************************************************** CLOCK.CPP
  2.  *                                                                          *
  3.  *                Analog Clock for Presentation Manager                     *
  4.  *                                                                          *
  5.  *                Original program by Charles Petzold                       *
  6.  *                                                                          *
  7.  ****************************************************************************/
  8.  
  9. //
  10. // Things to do:
  11. //
  12. //   (1) Show Date (optional)
  13. //
  14.  
  15. #define INCL_BASE
  16. #define INCL_PM
  17. #include <os2.h>
  18.  
  19. #include <process.h>
  20. #include <stdarg.h>
  21. #include <stddef.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25.  
  26. #include "debug.h"
  27. #include "helpwin.h"
  28. #include "module.h"
  29. #include "process.h"
  30. #include "profile.h"
  31. #include "restring.h"
  32. #include "support.h"
  33. #include "window.h"
  34.  
  35. #include "about.h"
  36. #include "config.h"
  37.  
  38. #include "clock.h"
  39.  
  40.  
  41. /****************************************************************************
  42.  *                                                                          *
  43.  *                       Definitions & Declarations                         *
  44.  *                                                                          *
  45.  ****************************************************************************/
  46.  
  47.   // Constants
  48.  
  49. #define DATEFMT_MM_DD_YY    (0x0000)
  50. #define DATEFMT_DD_MM_YY    (0x0001)
  51. #define DATEFMT_YY_MM_DD    (0x0002)
  52.  
  53. enum { ALERT_TASKCOUNT, ALERT_LOAD } ;
  54.  
  55. #define WM_REFRESH WM_USER
  56.  
  57.  
  58.   // Type Definitions
  59.  
  60. typedef struct {
  61.   SHORT cxClient ;
  62.   SHORT cyClient ;
  63.   SHORT cxPixelDiam ;
  64.   SHORT cyPixelDiam ;
  65. }
  66. WINDOWINFO, *PWINDOWINFO ;
  67.  
  68. typedef struct {
  69.   volatile BOOL Active ;
  70.   volatile PULONG Counter ;
  71.   HWND Owner ;
  72. }
  73. MONITOR_PARMS, *PMONITOR_PARMS ;
  74.  
  75. typedef struct {
  76.   volatile BOOL Active ;
  77.   volatile PULONG Counter ;
  78. }
  79. COUNTER_PARMS, *PCOUNTER_PARMS ;
  80.  
  81. typedef struct {      // Parameters saved to system.
  82.  
  83.   SWP    Position ;             // Window size & location.
  84.   BOOL   fPosition ;
  85.  
  86.   BOOL   Hour24 ;               // User options.
  87.   BOOL   fHour24 ;
  88.  
  89.   BOOL   HideControls ;
  90.   BOOL   fHideControls ;
  91.  
  92.   BOOL   Chime ;
  93.   BOOL   fChime ;
  94.  
  95.   BOOL   Float ;
  96.   BOOL   fFloat ;
  97.  
  98.   BOOL   Animate ;
  99.   BOOL   fAnimate ;
  100.  
  101.   BOOL   Analog ;
  102.   BOOL   fAnalog ;
  103.  
  104.   BOOL   AlertType ;
  105.   BOOL   fAlertType ;
  106.  
  107.   USHORT AlertLevels [2] [2] ;
  108.   BOOL   fAlertLevels ;
  109.  
  110.   CHAR   FontNameSize [80] ;    // Presentation Parameters
  111.   BOOL   fFontNameSize ;
  112.  
  113.   COLOR  BackColor ;
  114.   BOOL   fBackColor ;
  115.  
  116.   COLOR  TextColor ;
  117.   BOOL   fTextColor ;
  118. }
  119. INIDATA, *PINIDATA ;
  120.  
  121. typedef struct {
  122.  
  123.   Process *Proc ;
  124.   Module  *Library ;
  125.   Profile *IniFile ;
  126.  
  127.   INIDATA IniData ;
  128.  
  129.   HWND hwndTitleBar ;
  130.   HWND hwndSysMenu ;
  131.   HWND hwndMinMax ;
  132.  
  133.   DATETIME PreviousDateTime ;
  134.   USHORT PreviousHour ;
  135.   LONG xPixelsPerMeter, yPixelsPerMeter ;
  136.   WINDOWINFO wi ;
  137.  
  138.   USHORT Alert ;
  139.  
  140.   ULONG MaxCount ;
  141.   ULONG IdleCounter ;
  142.   ULONG IdleCount ;
  143.  
  144.   TID   IdleLoopTID ;
  145.   COUNTER_PARMS IdleLoopParms ;
  146.  
  147.   TID   MonitorTID ;
  148.   MONITOR_PARMS MonitorParms ;
  149.  
  150.   COUNTRYINFO CountryInfo ;
  151. }
  152. DATA, *PDATA ;
  153.  
  154. typedef struct {
  155.    short Filler ;
  156.    Process *Proc ;
  157.    Module *Library ;
  158.    Profile *IniFile ;
  159.    BOOL Analog ;
  160.    BOOL fAnalog ;
  161. }
  162. PARMS, *PPARMS ;
  163.  
  164.  
  165.   // Function Prototypes
  166.  
  167. extern int main ( int argc, char *argv[] ) ;
  168.  
  169. static FNWP MessageProcessor ;
  170.  
  171. static METHODFUNCTION Create ;
  172. static METHODFUNCTION Destroy ;
  173. static METHODFUNCTION Size ;
  174. static METHODFUNCTION SaveApplication ;
  175. static METHODFUNCTION Paint ;
  176. static METHODFUNCTION Command ;
  177. static METHODFUNCTION ResetDefaults ;
  178. static METHODFUNCTION HideControlsCmd ;
  179. static METHODFUNCTION Configure ;
  180. static METHODFUNCTION About ;
  181. static METHODFUNCTION ButtonDown ;
  182. static METHODFUNCTION ButtonDblClick ;
  183. static METHODFUNCTION PresParamChanged ;
  184. static METHODFUNCTION SysColorChange ;
  185. static METHODFUNCTION QueryKeysHelp ;
  186. static METHODFUNCTION HelpError ;
  187. static METHODFUNCTION ExtHelpUndefined ;
  188. static METHODFUNCTION HelpSubitemNotFound ;
  189. static METHODFUNCTION Refresh ;
  190.  
  191. static int GetIniData ( HINI IniHandle, PINIDATA IniData ) ;
  192. static VOID PutIniData ( HINI IniHandle, PINIDATA IniData ) ;
  193.  
  194. static VOID RotatePoint ( POINTL aptl[],  SHORT sNum, SHORT sAngle ) ;
  195. static VOID ScalePoint ( POINTL aptl[], SHORT sNum, PWINDOWINFO pwi ) ;
  196. static VOID TranslatePoint ( POINTL aptl[], SHORT sNum, PWINDOWINFO pwi ) ;
  197. static VOID DrawHand ( HPS hPS, POINTL aptlIn[], SHORT sNum, SHORT sAngle,
  198.   PWINDOWINFO pwi ) ;
  199. static void PaintBackground ( HWND hwnd, HPS hPS, PDATA Data, BOOL MustPaint ) ;
  200. static void PaintBorder ( HWND hwnd, HPS hPS, PDATA Data, BOOL MustPaint ) ;
  201. static void PaintDigitalTime ( HWND hwnd, HPS hPS, PDATA Data, PDATETIME DateTime ) ;
  202.  
  203. static void HideControls
  204. (
  205.   BOOL fHide,
  206.   HWND hwndFrame,
  207.   HWND hwndSysMenu,
  208.   HWND hwndTitleBar,
  209.   HWND hwndMinMax
  210. ) ;
  211.  
  212. static void _Optlink MonitorThread ( PVOID Parameter ) ;
  213.  
  214. static ULONG CalibrateLoadMeter ( void ) ;
  215.  
  216. static void _Optlink CounterThread ( PVOID Parameter ) ;
  217.  
  218.  
  219.   // Global Data
  220.  
  221. HMODULE LibraryHandle ;
  222.  
  223.  
  224. /****************************************************************************
  225.  *                                                                          *
  226.  *      Program Mainline                                                    *
  227.  *                                                                          *
  228.  ****************************************************************************/
  229.  
  230. extern int main ( int argc, char *argv[] )
  231. {
  232.  /***************************************************************************
  233.   * Initialize the process.                                                 *
  234.   ***************************************************************************/
  235.  
  236.   Process Proc ;
  237.  
  238.  /***************************************************************************
  239.   * Now WIN and GPI calls will work.  Open the language DLL.                *
  240.   ***************************************************************************/
  241.  
  242.   Module Library ( PSZ(PROGRAM_NAME) ) ;
  243.   LibraryHandle = Library.QueryHandle() ;
  244.  
  245.  /***************************************************************************
  246.   * Get the program title.                                                  *
  247.   ***************************************************************************/
  248.  
  249.   ResourceString Title ( Library.QueryHandle(), IDS_TITLE ) ;
  250.  
  251.  /***************************************************************************
  252.   * Decipher command-line parameters.                                       *
  253.   ***************************************************************************/
  254.  
  255.   ResourceString ResetCommand ( Library.QueryHandle(), IDS_PARMS_RESET ) ;
  256.   ResourceString AnalogCommand ( Library.QueryHandle(), IDS_PARMS_ANALOG ) ;
  257.   ResourceString DigitalCommand ( Library.QueryHandle(), IDS_PARMS_DIGITAL ) ;
  258.  
  259.   BOOL Reset = FALSE ;
  260.   BOOL Analog = TRUE ;
  261.   BOOL fAnalog = FALSE ;
  262.  
  263.   while ( --argc ) {
  264.  
  265.     argv ++ ;
  266.   
  267.     if ( *argv[0] == '?' ) {
  268.       ResourceString Message ( Library.QueryHandle(), IDS_PARAMETERLIST ) ;
  269.       WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, PSZ(Message),
  270.         PSZ(Title), 0, MB_ENTER | MB_NOICON ) ;
  271.       return ( 0 ) ;
  272.     }
  273.  
  274.     if ( !stricmp ( *argv, PCHAR(ResetCommand) ) ) {
  275.       Reset = TRUE ;
  276.       continue ;
  277.     }
  278.  
  279.     if ( !stricmp ( *argv, PCHAR(AnalogCommand) ) ) {
  280.       Analog = TRUE ;
  281.       fAnalog = TRUE ;
  282.       continue ;
  283.     }
  284.  
  285.     if ( !stricmp ( *argv, PCHAR(DigitalCommand) ) ) {
  286.       Analog = FALSE ;
  287.       fAnalog = TRUE ;
  288.       continue ;
  289.     }
  290.  
  291.     {
  292.       ResourceString Format ( Library.QueryHandle(), IDS_ERROR_INVALIDPARM ) ;
  293.       BYTE Message [200] ;
  294.       sprintf ( PCHAR(Message), PCHAR(Format), *argv ) ;
  295.       WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, Message,
  296.         PSZ(Title), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  297.       abort ( ) ;
  298.     }
  299.   }
  300.  
  301.  /***************************************************************************
  302.   * Create the help instance.                                               *
  303.   ***************************************************************************/
  304.  
  305.   ResourceString HelpTitle ( Library.QueryHandle(), IDS_HELPTITLE ) ;
  306.  
  307.   HelpWindow Help ( Proc.QueryAnchor(), 0,
  308.     ID_MAIN, PSZ(PROGRAM_NAME ".hlp"), PSZ(HelpTitle) ) ;
  309.  
  310.   if ( Help.QueryHandle() == 0 ) {
  311.     ERRORID Error = WinGetLastError ( Proc.QueryAnchor() ) ;
  312.     ResourceString Format ( Library.QueryHandle(), IDS_ERROR_CREATEHELP ) ;
  313.     CHAR Message [200] ;
  314.     sprintf ( Message, PCHAR(Format), Error ) ;
  315. //  Log ( "%s", Message ) ;
  316.     WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, PSZ(Message),
  317.       PSZ(Title), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  318.   }
  319.  
  320.  /***************************************************************************
  321.   * Open/create the profile file.  Reset if requested.                      *
  322.   ***************************************************************************/
  323.  
  324.   Profile IniFile ( PSZ(PROGRAM_NAME),
  325.     Proc.QueryAnchor(), Library.QueryHandle(),
  326.     IDD_PROFILE_PATH, Help.QueryHandle(), Reset ) ;
  327.  
  328.   if ( IniFile.QueryHandle() == 0 ) {
  329.     ResourceString Message ( Library.QueryHandle(), IDS_ERROR_PRFOPENPROFILE ) ;
  330.     Log ( "%s", PSZ(Message) ) ;
  331.     WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, PSZ(Message),
  332.       PSZ(Title), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  333.     abort ( ) ;
  334.   }
  335.  
  336.  /***************************************************************************
  337.   * Read the profile to find out if we're to animate the frame window.      *
  338.   ***************************************************************************/
  339.  
  340.   BOOL Animate = FALSE ;
  341.   ULONG Size ;
  342.   if
  343.   (
  344.     PrfQueryProfileSize ( IniFile.QueryHandle(), PSZ(PROGRAM_NAME), PSZ("Animate"), &Size )
  345.     AND
  346.     ( ( Size == sizeof(Animate) ) OR ( Size == sizeof(short) ) )
  347.     AND
  348.     PrfQueryProfileData ( IniFile.QueryHandle(), PSZ(PROGRAM_NAME), PSZ("Animate"), &Animate, &Size )
  349.   )
  350.   {
  351.     ;
  352.   }
  353.  
  354.  /***************************************************************************
  355.   * Create the frame window.                                                *
  356.   ***************************************************************************/
  357.  
  358.   FRAMECDATA FrameControlData ;
  359.   FrameControlData.cb = sizeof(FrameControlData) ;
  360.   FrameControlData.flCreateFlags =
  361.     FCF_TITLEBAR | FCF_SYSMENU | FCF_SIZEBORDER |
  362.     FCF_MINMAX | FCF_NOBYTEALIGN | FCF_ACCELTABLE ;
  363.   FrameControlData.hmodResources = 0 ;
  364.   FrameControlData.idResources = ID_MAIN ;
  365.  
  366.   Window Frame ( HWND_DESKTOP, WC_FRAME, PSZ(Title),
  367.     Animate ? WS_ANIMATE : 0,
  368.     0, 0, 0, 0, HWND_DESKTOP, HWND_TOP, ID_MAIN,
  369.     &FrameControlData, NULL ) ;
  370.  
  371.   if ( Frame.QueryHandle() == 0 ) {
  372.     ERRORID Error = WinGetLastError ( Proc.QueryAnchor() ) ;
  373.     ResourceString Format ( Library.QueryHandle(), IDS_ERROR_CREATEFRAME ) ;
  374.     CHAR Message [200] ;
  375.     sprintf ( Message, PCHAR(Format), Error ) ;
  376.     Log ( "%s", Message ) ;
  377.     WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, PSZ(Message),
  378.       PSZ(Title), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  379.     abort ( ) ;
  380.   }
  381.  
  382.  /***************************************************************************
  383.   * Associate the help instance with the frame window.                      *
  384.   ***************************************************************************/
  385.  
  386.   if ( Help.QueryHandle() ) {
  387.     WinAssociateHelpInstance ( Help.QueryHandle(), Frame.QueryHandle() ) ;
  388.   }
  389.  
  390.  /***************************************************************************
  391.   * Register the client window class.                                       *
  392.   ***************************************************************************/
  393.  
  394.   if
  395.   (
  396.     !WinRegisterClass
  397.     (
  398.       Proc.QueryAnchor(),
  399.       PSZ(CLASS_NAME),
  400.       MessageProcessor,
  401.       CS_MOVENOTIFY,
  402.       sizeof(PVOID)
  403.     )
  404.   )
  405.   {
  406.     ERRORID Error = WinGetLastError ( Proc.QueryAnchor() ) ;
  407.     ResourceString Format ( Library.QueryHandle(), IDS_ERROR_WINREGISTERCLASS ) ;
  408.     CHAR Message [200] ;
  409.     sprintf ( Message, PCHAR(Format), CLASS_NAME, Error ) ;
  410.     Log ( "%s", Message ) ;
  411.     WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, PSZ(Message),
  412.       PSZ(Title), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  413.     abort ( ) ;
  414.   }
  415.  
  416.  /***************************************************************************
  417.   * Create client window.  If this fails, destroy frame and return.         *
  418.   ***************************************************************************/
  419.  
  420.   PARMS Parms ;
  421.   Parms.Filler = 0 ;
  422.   Parms.Proc = & Proc ;
  423.   Parms.Library = & Library ;
  424.   Parms.IniFile = & IniFile ;
  425.   Parms.Analog = Analog ;
  426.   Parms.fAnalog = fAnalog ;
  427.  
  428.   Window Client ( Frame.QueryHandle(), PSZ(CLASS_NAME), PSZ(""), 0, 0, 0, 0, 0,
  429.      Frame.QueryHandle(), HWND_BOTTOM, FID_CLIENT, &Parms, NULL ) ;
  430.  
  431.   if ( Client.QueryHandle() == 0 ) {
  432.     ERRORID Error = WinGetLastError ( Proc.QueryAnchor() ) ;
  433.     ResourceString Format ( Library.QueryHandle(), IDS_ERROR_CREATECLIENT ) ;
  434.     CHAR Message [200] ;
  435.     sprintf ( Message, PCHAR(Format), Error ) ;
  436.     Log ( "%s", Message ) ;
  437.     WinMessageBox ( HWND_DESKTOP, HWND_DESKTOP, PSZ(Message),
  438.       PSZ(Title), 0, MB_ENTER | MB_ICONEXCLAMATION ) ;
  439.     abort ( ) ;
  440.   }
  441.  
  442.  /***************************************************************************
  443.   * Wait for and process messages to the window's queue.  Terminate         *
  444.   *   when the WM_QUIT message is received.                                 *
  445.   ***************************************************************************/
  446.  
  447.   QMSG QueueMessage ;
  448.   while ( WinGetMsg ( Proc.QueryAnchor(), &QueueMessage, 0, 0, 0 ) ) {
  449.     WinDispatchMsg ( Proc.QueryAnchor(), &QueueMessage ) ;
  450.   }
  451.  
  452.  /***************************************************************************
  453.   * Discard all that was requested of the system and terminate.             *
  454.   ***************************************************************************/
  455.  
  456.   return ( 0 ) ;
  457. }
  458.  
  459. /****************************************************************************
  460.  *                                                                          *
  461.  *      Window Message Processor                                            *
  462.  *                                                                          *
  463.  ****************************************************************************/
  464.  
  465. static MRESULT EXPENTRY MessageProcessor
  466. (
  467.   HWND hwnd,
  468.   ULONG msg,
  469.   MPARAM mp1,
  470.   MPARAM mp2
  471. )
  472. {
  473.  /***************************************************************************
  474.   * Dispatch the message according to the method table and return the       *
  475.   *   result.  Any messages not defined above get handled by the system     *
  476.   *   default window processor.                                             *
  477.   ***************************************************************************/
  478.  
  479.   static METHOD Methods [] =
  480.   {
  481.     { WM_CREATE,                Create              },
  482.     { WM_DESTROY,               Destroy             },
  483.     { WM_SIZE,                  Size                },
  484.     { WM_MOVE,                  Size                },
  485.     { WM_SAVEAPPLICATION,       SaveApplication     },
  486.     { WM_PAINT,                 Paint               },
  487.     { WM_COMMAND,               Command             },
  488.     { WM_BUTTON1DOWN,           ButtonDown          },
  489.     { WM_BUTTON2DOWN,           ButtonDown          },
  490.     { WM_BUTTON1DBLCLK,         ButtonDblClick      },
  491.     { WM_BUTTON2DBLCLK,         ButtonDblClick      },
  492.     { WM_PRESPARAMCHANGED,      PresParamChanged    },
  493.     { WM_SYSCOLORCHANGE,        SysColorChange      },
  494.     { HM_QUERY_KEYS_HELP,       QueryKeysHelp       },
  495.     { HM_ERROR,                 HelpError           },
  496.     { HM_EXT_HELP_UNDEFINED,    ExtHelpUndefined    },
  497.     { HM_HELPSUBITEM_NOT_FOUND, HelpSubitemNotFound },
  498.     { WM_REFRESH,               Refresh             }
  499.   } ;
  500.  
  501.   return ( DispatchMessage ( hwnd, msg, mp1, mp2, Methods, sizeof(Methods)/sizeof(Methods[0]), WinDefWindowProc ) ) ;
  502. }
  503.  
  504. /****************************************************************************
  505.  *                                                                          *
  506.  *      Initialize main window.                                             *
  507.  *                                                                          *
  508.  ****************************************************************************/
  509.  
  510. static MRESULT APIENTRY Create
  511.   HWND hwnd, 
  512.   ULONG msg, 
  513.   MPARAM mp1, 
  514.   MPARAM mp2
  515. )
  516. {
  517.  /***************************************************************************
  518.   * Allocate instance data.                                                 *
  519.   ***************************************************************************/
  520.  
  521.   PDATA Data = PDATA ( malloc ( sizeof(DATA) ) ) ;
  522.  
  523.   memset ( Data, 0, sizeof(DATA) ) ;
  524.  
  525.   WinSetWindowPtr ( hwnd, QWL_USER, Data ) ;
  526.  
  527.  /***************************************************************************
  528.   * Grab any parameters from the WM_CREATE message.                         *
  529.   ***************************************************************************/
  530.  
  531.   PPARMS Parms = PPARMS ( PVOIDFROMMP ( mp1 ) ) ;
  532.  
  533.   Data->Proc = Parms->Proc ;
  534.   Data->Library = Parms->Library ;
  535.   Data->IniFile = Parms->IniFile ;
  536.  
  537.  /***************************************************************************
  538.   * Get profile data. Try the OS2.INI first, then try for private INI.      *
  539.   *   If obtained from OS2.INI, erase it afterwards.                        *
  540.   ***************************************************************************/
  541.  
  542.   if ( GetIniData ( HINI_USERPROFILE, &Data->IniData ) )
  543.   {
  544.     GetIniData ( Data->IniFile->QueryHandle(), &Data->IniData ) ;
  545.   }
  546.   else
  547.   {
  548.     PrfWriteProfileData ( HINI_USERPROFILE, PSZ(PROGRAM_NAME), PSZ(NULL), PSZ(NULL), 0 ) ;
  549.   }
  550.  
  551.   if ( Parms->fAnalog )
  552.   {
  553.     Data->IniData.Analog = Parms->Analog ;
  554.     Data->IniData.fAnalog = TRUE ;
  555.   }
  556.  
  557.  /***************************************************************************
  558.   * Get country information.                                                *
  559.   ***************************************************************************/
  560.  
  561.   {
  562.     COUNTRYCODE CountryCode ;
  563.     ULONG Count ;
  564.     ULONG Status ;
  565.  
  566.     CountryCode.country = 0 ;
  567.     CountryCode.codepage = 0 ;
  568.  
  569.     Status = DosGetCtryInfo ( sizeof(Data->CountryInfo), &CountryCode,
  570.       &Data->CountryInfo, &Count ) ;
  571.     if ( Status )
  572.     {
  573.       BYTE Message [80] ;
  574.       WinLoadMessage ( Data->Proc->QueryAnchor(), Data->Library->QueryHandle(), IDS_ERROR_DOSGETCTRYINFO,
  575.         sizeof(Message), Message ) ;
  576.       Debug ( hwnd, PCHAR(Message), Status ) ;
  577.       Data->CountryInfo.fsDateFmt = DATEFMT_MM_DD_YY ;
  578.       Data->CountryInfo.fsTimeFmt = 0 ;
  579.       Data->CountryInfo.szDateSeparator[0] = '/' ;
  580.       Data->CountryInfo.szDateSeparator[1] = 0 ;
  581.       Data->CountryInfo.szTimeSeparator[0] = ':' ;
  582.       Data->CountryInfo.szTimeSeparator[1] = 0 ;
  583.       Data->CountryInfo.szThousandsSeparator[0] = ',' ;
  584.       Data->CountryInfo.szThousandsSeparator[1] = 0 ;
  585.     }
  586.   }
  587.  
  588.   if ( NOT Data->IniData.fHour24 )
  589.   {
  590.     Data->IniData.Hour24 = Data->CountryInfo.fsTimeFmt ;
  591.   }
  592.  
  593.  /***************************************************************************
  594.   * Get initial time.                                                       *
  595.   ***************************************************************************/
  596.  
  597.   DosGetDateTime ( &Data->PreviousDateTime ) ;
  598.  
  599.   Data->PreviousHour = ( Data->PreviousDateTime.hours * 5 ) % 60
  600.     + Data->PreviousDateTime.minutes/12 ;
  601.  
  602.  /***************************************************************************
  603.   * Get the frame handle.                                                   *
  604.   ***************************************************************************/
  605.  
  606.   HWND FrameWindow = WinQueryWindow ( hwnd, QW_PARENT ) ;
  607.  
  608.  /***************************************************************************
  609.   * Get the control window handles.                                         *
  610.   ***************************************************************************/
  611.  
  612.   Data->hwndSysMenu  = WinWindowFromID ( FrameWindow, FID_SYSMENU  ) ;
  613.   Data->hwndTitleBar = WinWindowFromID ( FrameWindow, FID_TITLEBAR ) ;
  614.   Data->hwndMinMax   = WinWindowFromID ( FrameWindow, FID_MINMAX   ) ;
  615.  
  616.  /***************************************************************************
  617.   * Add basic extensions to the system menu.                                *
  618.   ***************************************************************************/
  619.  
  620.   static MENUITEM MenuSeparator =
  621.     { MIT_END, MIS_SEPARATOR, 0, 0, 0, 0 } ;
  622.  
  623.   AddSysMenuItem ( FrameWindow, &MenuSeparator, PSZ(NULL) ) ;
  624.  
  625.   static MENUITEM MenuItems [] =
  626.   {
  627.     { MIT_END, MIS_TEXT,      0, IDM_SAVE_APPLICATION, 0, 0 },
  628.     { MIT_END, MIS_TEXT,      0, IDM_RESET_DEFAULTS,   0, 0 },
  629.     { MIT_END, MIS_TEXT,      0, IDM_HIDE_CONTROLS,    0, 0 },
  630.     { MIT_END, MIS_TEXT,      0, IDM_CONFIGURE,        0, 0 },
  631.   } ;
  632.  
  633.   for ( int i=0; i<sizeof(MenuItems)/sizeof(MenuItems[0]); i++ )
  634.   {
  635.     ResourceString MenuText ( Data->Library->QueryHandle(), i+IDS_SAVE_APPLICATION ) ;
  636.     AddSysMenuItem ( FrameWindow, MenuItems+i, PSZ(MenuText) ) ;
  637.   }
  638.  
  639.  /***************************************************************************
  640.   * Add 'About' to the system menu.                                         *
  641.   ***************************************************************************/
  642.  
  643.   AddSysMenuItem ( FrameWindow, &MenuSeparator, PSZ(NULL) ) ;
  644.  
  645.   ResourceString AboutText ( Data->Library->QueryHandle(), IDS_ABOUT ) ;
  646.  
  647.   static MENUITEM MenuAbout =
  648.     { MIT_END, MIS_TEXT, 0, IDM_ABOUT, 0, 0 } ;
  649.  
  650.   AddSysMenuItem ( FrameWindow, &MenuAbout, PSZ(AboutText) ) ;
  651.  
  652.  /***************************************************************************
  653.   * Add 'Help' to the system menu.                                          *
  654.   ***************************************************************************/
  655.  
  656.   ResourceString HelpText ( Data->Library->QueryHandle(), IDS_HELP ) ;
  657.  
  658.   static MENUITEM MenuHelp =
  659.     { MIT_END, MIS_HELP, 0, 0, 0, 0 } ;
  660.  
  661.   AddSysMenuItem ( FrameWindow, &MenuHelp, PSZ(HelpText) ) ;
  662.  
  663.  /***************************************************************************
  664.   * Calibrate the old-style load meter, if the high resolution timer's      *
  665.   *   available.                                                            *
  666.   ***************************************************************************/
  667.  
  668.   Data->MaxCount = CalibrateLoadMeter ( ) ;
  669.   Data->MaxCount = (ULONG) max ( 1L, Data->MaxCount ) ;
  670.  
  671.  /***************************************************************************
  672.   * Start the load meter.  Put it to sleep if we're not using it.           *
  673.   ***************************************************************************/
  674.  
  675.   Data->IdleLoopParms.Active = TRUE ;
  676.   Data->IdleLoopParms.Counter = & Data->IdleCounter ;
  677.   Data->IdleLoopTID = _beginthread ( CounterThread, NULL, 0x3000, &Data->IdleLoopParms ) ;
  678.   DosSetPrty ( PRTYS_THREAD, PRTYC_IDLETIME, PRTYD_MINIMUM, Data->IdleLoopTID ) ;
  679.   DosSuspendThread ( Data->IdleLoopTID ) ;
  680.  
  681.   Data->IdleCount = 0 ;
  682.   Data->IdleCounter = 0 ;
  683.  
  684.   if ( Data->IniData.AlertType == ALERT_LOAD )
  685.   {
  686.     DosResumeThread ( Data->IdleLoopTID ) ;
  687.   }
  688.  
  689.   Data->MonitorParms.Active = TRUE ;
  690.   Data->MonitorParms.Counter = & Data->IdleCounter ;
  691.   Data->MonitorParms.Owner = hwnd ;
  692.   Data->MonitorTID = _beginthread ( MonitorThread, NULL, 0x3000, &Data->MonitorParms ) ;
  693.  
  694.  /***************************************************************************
  695.   * Add the program to the system task list.                                *
  696.   ***************************************************************************/
  697.  
  698.   ResourceString Title ( Data->Library->QueryHandle(), IDS_TITLE ) ;
  699.   Add2TaskList ( FrameWindow, PSZ(Title) ) ;
  700.  
  701.  /***************************************************************************
  702.   * Get device capabilities before you mess around with resizing.           *
  703.   ***************************************************************************/
  704.  
  705.   HPS hPS = WinGetPS ( hwnd ) ;
  706.   HDC hDC = GpiQueryDevice ( hPS ) ;
  707.   DevQueryCaps ( hDC, CAPS_VERTICAL_RESOLUTION, 1L,
  708.     &Data->yPixelsPerMeter ) ;
  709.   DevQueryCaps ( hDC, CAPS_HORIZONTAL_RESOLUTION, 1L,
  710.     &Data->xPixelsPerMeter ) ;
  711.   WinReleasePS ( hPS ) ;
  712.  
  713.  /***************************************************************************
  714.   * If window hasn't been positioned before, set the default position.      *
  715.   ***************************************************************************/
  716.  
  717.   RECTL Rectangle ;
  718.   if ( NOT Data->IniData.fPosition )
  719.   {
  720.     WinQueryWindowRect ( HWND_DESKTOP, &Rectangle ) ;
  721.  
  722.     Rectangle.xLeft = Rectangle.xRight - Rectangle.xRight / 4 ;
  723.     Rectangle.yBottom = Rectangle.yTop - Rectangle.yTop / 3 ;
  724.  
  725.     Data->IniData.Position.x = (SHORT) Rectangle.xLeft ;
  726.     Data->IniData.Position.y = (SHORT) Rectangle.yBottom ;
  727.  
  728.     Data->IniData.Position.cx = (SHORT) ( Rectangle.xRight - Rectangle.xLeft ) ;
  729.     Data->IniData.Position.cy = (SHORT) ( Rectangle.yTop - Rectangle.yBottom ) ;
  730.   }
  731.  
  732.  /***************************************************************************
  733.   * Position & size the window.                                             *
  734.   ***************************************************************************/
  735.  
  736.   Rectangle.xLeft   = Data->IniData.Position.x ;
  737.   Rectangle.xRight  = Data->IniData.Position.x + Data->IniData.Position.cx ;
  738.   Rectangle.yBottom = Data->IniData.Position.y ;
  739.   Rectangle.yTop    = Data->IniData.Position.y + Data->IniData.Position.cy ;
  740.  
  741.   if ( Data->IniData.HideControls )
  742.   {
  743.     WinSetParent ( Data->hwndSysMenu,  HWND_OBJECT, FALSE ) ;
  744.     WinSetParent ( Data->hwndTitleBar, HWND_OBJECT, FALSE ) ;
  745.     WinSetParent ( Data->hwndMinMax,   HWND_OBJECT, FALSE ) ;
  746.  
  747.     WinSendMsg ( FrameWindow, WM_UPDATEFRAME,
  748.       MPFROMSHORT ( FCF_TITLEBAR | FCF_SYSMENU | FCF_MINBUTTON ), 0L ) ;
  749.  
  750.     WinCalcFrameRect ( FrameWindow, &Rectangle, TRUE ) ;
  751.  
  752.     WinSetParent ( Data->hwndSysMenu,  FrameWindow, TRUE ) ;
  753.     WinSetParent ( Data->hwndTitleBar, FrameWindow, TRUE ) ;
  754.     WinSetParent ( Data->hwndMinMax,   FrameWindow, TRUE ) ;
  755.  
  756.     WinSendMsg ( FrameWindow, WM_UPDATEFRAME,
  757.       MPFROMSHORT ( FCF_TITLEBAR | FCF_SYSMENU | FCF_MINBUTTON ), 0L ) ;
  758.  
  759.     WinCalcFrameRect ( FrameWindow, &Rectangle, FALSE ) ;
  760.   }
  761.  
  762.   WinSetWindowPos ( FrameWindow, HWND_BOTTOM,
  763.     (SHORT) Rectangle.xLeft, (SHORT) Rectangle.yBottom,
  764.     (SHORT) ( Rectangle.xRight - Rectangle.xLeft ),
  765.     (SHORT) ( Rectangle.yTop - Rectangle.yBottom ),
  766.     SWP_SIZE | SWP_MOVE | SWP_ZORDER |
  767.     ( Data->IniData.Position.fl & SWP_MINIMIZE ) |
  768.     ( Data->IniData.Position.fl & SWP_MAXIMIZE ) |
  769.     ( Data->IniData.Position.fl & SWP_RESTORE ) ) ;
  770.  
  771.  /***************************************************************************
  772.   * Hide the controls if so configured and not minimized.                   *
  773.   ***************************************************************************/
  774.  
  775.   if ( Data->IniData.HideControls
  776.     AND NOT ( Data->IniData.Position.fl & SWP_MINIMIZE ) )
  777.   {
  778.     CheckMenuItem ( FrameWindow, FID_SYSMENU, IDM_HIDE_CONTROLS, Data->IniData.HideControls ) ;
  779.  
  780.     HideControls
  781.     (
  782.       TRUE,
  783.       FrameWindow,
  784.       Data->hwndSysMenu,
  785.       Data->hwndTitleBar,
  786.       Data->hwndMinMax
  787.     ) ;
  788.   }
  789.  
  790.  /***************************************************************************
  791.   * Get the saved presentation parameters and reinstate them.               *
  792.   ***************************************************************************/
  793.  
  794.   if ( Data->IniData.fFontNameSize )
  795.   {
  796.     WinSetPresParam ( hwnd, PP_FONTNAMESIZE,
  797.       strlen(Data->IniData.FontNameSize)+1, Data->IniData.FontNameSize ) ;
  798.   }
  799.  
  800.   if ( Data->IniData.fBackColor )
  801.   {
  802.     WinSetPresParam ( hwnd, PP_BACKGROUNDCOLOR,
  803.       sizeof(Data->IniData.BackColor), &Data->IniData.BackColor ) ;
  804.   }
  805.  
  806.   if ( Data->IniData.fTextColor )
  807.   {
  808.     WinSetPresParam ( hwnd, PP_FOREGROUNDCOLOR,
  809.       sizeof(Data->IniData.TextColor), &Data->IniData.TextColor ) ;
  810.   }
  811.  
  812.  /***************************************************************************
  813.   * Now that the window's in order, make it visible.                        *
  814.   ***************************************************************************/
  815.  
  816.   WinShowWindow ( FrameWindow, TRUE ) ;
  817.  
  818.  /***************************************************************************
  819.   * Success?  Return no error.                                              *
  820.   ***************************************************************************/
  821.  
  822.   return ( MRFROMSHORT ( 0 ) ) ;
  823. }
  824.  
  825. /****************************************************************************
  826.  *                                                                          *
  827.  *      Destroy main window.                                                *
  828.  *                                                                          *
  829.  ****************************************************************************/
  830.  
  831. static MRESULT APIENTRY Destroy
  832.   HWND hwnd, 
  833.   ULONG msg, 
  834.   MPARAM mp1, 
  835.   MPARAM mp2
  836. )
  837. {
  838.  /***************************************************************************
  839.   * Find the instance data.                                                 *
  840.   ***************************************************************************/
  841.  
  842.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  843.  
  844.  /***************************************************************************
  845.   * Kill the extra threads.                                                 *
  846.   ***************************************************************************/
  847.  
  848.   DosResumeThread ( Data->MonitorTID ) ;
  849.   Data->MonitorParms.Active = FALSE ;
  850.   DosWaitThread ( &Data->MonitorTID, DCWW_WAIT ) ;
  851.  
  852.   DosResumeThread ( Data->IdleLoopTID ) ;
  853.   Data->IdleLoopParms.Active = FALSE ;
  854.   DosWaitThread ( &Data->IdleLoopTID, DCWW_WAIT ) ;
  855.  
  856.  /***************************************************************************
  857.   * Release the instance memory.                                            *
  858.   ***************************************************************************/
  859.  
  860.   free ( Data ) ;
  861.  
  862.  /***************************************************************************
  863.   * We're done.                                                             *
  864.   ***************************************************************************/
  865.  
  866.   return ( MRFROMSHORT ( 0 ) ) ;
  867. }
  868.  
  869. /****************************************************************************
  870.  *                                                                          *
  871.  *      Resize the main window.                                             *
  872.  *                                                                          *
  873.  ****************************************************************************/
  874.  
  875. static MRESULT APIENTRY Size
  876.   HWND hwnd, 
  877.   ULONG msg, 
  878.   MPARAM mp1, 
  879.   MPARAM mp2
  880. )
  881. {
  882.  /***************************************************************************
  883.   * Find the instance data.                                                 *
  884.   ***************************************************************************/
  885.  
  886.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  887.  
  888.  /***************************************************************************
  889.   * Find out the window's new position and size.                            *
  890.   ***************************************************************************/
  891.  
  892.   HWND FrameWindow = WinQueryWindow ( hwnd, QW_PARENT ) ;
  893.  
  894.   SWP Position ;
  895.   WinQueryWindowPos ( FrameWindow, &Position ) ;
  896.  
  897.   if ( NOT ( Position.fl & SWP_MINIMIZE )
  898.     AND NOT ( Position.fl & SWP_MAXIMIZE ) )
  899.   {
  900.     Data->IniData.Position.x = Position.x ;
  901.     Data->IniData.Position.y = Position.y ;
  902.  
  903.     Data->IniData.Position.cx = Position.cx ;
  904.     Data->IniData.Position.cy = Position.cy ;
  905.   }
  906.  
  907.  /***************************************************************************
  908.   * If the message was a sizing notification, recompute scaling factors.    *
  909.   ***************************************************************************/
  910.  
  911.   if ( msg == WM_SIZE )
  912.   {
  913.     Data->wi.cxClient = SHORT1FROMMP ( mp2 ) ;
  914.     Data->wi.cyClient = SHORT2FROMMP ( mp2 ) ;
  915.  
  916.     SHORT sDiamMM = (SHORT) min ( Data->wi.cxClient*1000L/Data->xPixelsPerMeter,
  917.       Data->wi.cyClient*1000L/Data->yPixelsPerMeter ) ;
  918.  
  919.     Data->wi.cxPixelDiam = (SHORT) ( Data->xPixelsPerMeter * sDiamMM / 1000 ) ;
  920.     Data->wi.cyPixelDiam = (SHORT) ( Data->yPixelsPerMeter * sDiamMM / 1000 ) ;
  921.   }
  922.  
  923.  /***************************************************************************
  924.   * If hiding the controls . . .                                            *
  925.   ***************************************************************************/
  926.  
  927.   if ( Data->IniData.HideControls )
  928.   {
  929.  
  930.    /*************************************************************************
  931.     * If changing to or from minimized state . . .                          *
  932.     *************************************************************************/
  933.  
  934.     if ( ( Position.fl & SWP_MINIMIZE ) != ( Data->IniData.Position.fl & SWP_MINIMIZE ) )
  935.     {
  936.  
  937.      /***********************************************************************
  938.       * Hide the controls if no longer minimized.                           *
  939.       ***********************************************************************/
  940.  
  941.       HideControls
  942.       (
  943.         NOT ( Position.fl & SWP_MINIMIZE ),
  944.         FrameWindow,
  945.         Data->hwndSysMenu,
  946.         Data->hwndTitleBar,
  947.         Data->hwndMinMax
  948.       ) ;
  949.     }
  950.   }
  951.  
  952.   Data->IniData.Position.fl = Position.fl ;
  953.  
  954.  /***************************************************************************
  955.   * We're done.                                                             *
  956.   ***************************************************************************/
  957.  
  958.   return ( 0 ) ;
  959. }
  960.  
  961. /****************************************************************************
  962.  *                                                                          *
  963.  *      Process SAVE APPLICATION message.                                   *
  964.  *                                                                          *
  965.  ****************************************************************************/
  966.  
  967. static MRESULT APIENTRY SaveApplication
  968.   HWND hwnd, 
  969.   ULONG msg, 
  970.   MPARAM mp1, 
  971.   MPARAM mp2
  972. )
  973. {
  974.  /***************************************************************************
  975.   * Find the instance data.                                                 *
  976.   ***************************************************************************/
  977.  
  978.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  979.  
  980.  /***************************************************************************
  981.   * Call function to put all profile data out to the system.                *
  982.   ***************************************************************************/
  983.  
  984.   PutIniData ( Data->IniFile->QueryHandle(), &Data->IniData ) ;
  985.  
  986.  /***************************************************************************
  987.   * We're done.  Let the system complete default processing.                *
  988.   ***************************************************************************/
  989.  
  990.   return ( WinDefWindowProc ( hwnd, WM_SAVEAPPLICATION, 0, 0 ) ) ;
  991. }
  992.  
  993. /****************************************************************************
  994.  *                                                                          *
  995.  *      Process timer message.                                              *
  996.  *                                                                          *
  997.  ****************************************************************************/
  998.  
  999. static MRESULT APIENTRY Refresh
  1000.   HWND hwnd, 
  1001.   ULONG msg, 
  1002.   MPARAM mp1, 
  1003.   MPARAM mp2
  1004. )
  1005. {
  1006.  /***************************************************************************
  1007.   *                             Declarations                                *
  1008.   ***************************************************************************/
  1009.  
  1010.   static POINTL
  1011.     aptlHour[5]   = { 0,-15,  10,0,  0,60,  -10,0,  0,-15 },
  1012.     aptlMinute[5] = { 0,-20,   5,0,  0,80,   -5,0,  0,-20 },
  1013.     aptlSecond[2] = { 0,  0,   0,80 } ;
  1014.  
  1015.  /***************************************************************************
  1016.   * Find the instance data.                                                 *
  1017.   ***************************************************************************/
  1018.  
  1019.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1020.  
  1021.  /***************************************************************************
  1022.   * If we're supposed to float the window, do so here.                      *
  1023.   ***************************************************************************/
  1024.  
  1025.   if ( Data->IniData.Float )
  1026.     WinSetWindowPos ( WinQueryWindow(hwnd,QW_PARENT), HWND_TOP, 0, 0, 0, 0, SWP_ZORDER ) ;
  1027.  
  1028.  /***************************************************************************
  1029.   * Save the idle counter.                                                  *
  1030.   ***************************************************************************/
  1031.  
  1032.   Data->IdleCount = LONGFROMMP ( mp1 ) ;
  1033.  
  1034.  /***************************************************************************
  1035.   * Get current time.                                                       *
  1036.   ***************************************************************************/
  1037.  
  1038.   DATETIME DateTime ;
  1039.   DosGetDateTime ( &DateTime ) ;
  1040.  
  1041.   USHORT Hour = ( ( DateTime.hours * 5 ) % 60 + DateTime.minutes / 12 ) ;
  1042.  
  1043.  /***************************************************************************
  1044.   * Get presentation space.                                                 *
  1045.   ***************************************************************************/
  1046.  
  1047.   HPS hPS = WinGetPS ( hwnd ) ;
  1048.   GpiCreateLogColorTable ( hPS, LCOL_RESET, LCOLF_RGB, 0L, 0L, PLONG(NULL) ) ;
  1049.  
  1050.  /***************************************************************************
  1051.   * If analog or minimized . . .                                            *
  1052.   ***************************************************************************/
  1053.  
  1054.   if ( Data->IniData.Analog OR ( Data->IniData.Position.fl & SWP_MINIMIZE ) )
  1055.   {
  1056.  
  1057.    /*************************************************************************
  1058.     * If a new minute has arrived, and the clock is minimized, clear it.    *
  1059.     *************************************************************************/
  1060.  
  1061.     if ( ( Data->IniData.Position.fl & SWP_MINIMIZE )
  1062.       AND ( DateTime.minutes != Data->PreviousDateTime.minutes ) )
  1063.     {
  1064.       PaintBackground ( hwnd, hPS, Data, TRUE ) ;
  1065.     }
  1066.  
  1067.    /*************************************************************************
  1068.     * Erase the old clock hands.                                            *
  1069.     *************************************************************************/
  1070.  
  1071.     GpiSetColor ( hPS, Data->IniData.BackColor ) ;
  1072.     if ( ( Data->wi.cxClient > 50 ) AND ( Data->wi.cyClient > 50 ) )
  1073.     {
  1074.       DrawHand ( hPS, aptlSecond, 2, Data->PreviousDateTime.seconds, &Data->wi ) ;
  1075.     }
  1076.  
  1077.     if ( ( Hour != Data->PreviousHour )
  1078.       OR ( DateTime.minutes != Data->PreviousDateTime.minutes ) )
  1079.     {
  1080.       DrawHand ( hPS, aptlHour,   5, Data->PreviousHour,             &Data->wi ) ;
  1081.       DrawHand ( hPS, aptlMinute, 5, Data->PreviousDateTime.minutes, &Data->wi ) ;
  1082.     }
  1083.  
  1084.    /*************************************************************************
  1085.     * Draw the new clock hands.                                             *
  1086.     *************************************************************************/
  1087.  
  1088.     GpiSetColor ( hPS, Data->IniData.TextColor ) ;
  1089.     DrawHand ( hPS, aptlHour,   5, Hour,             &Data->wi ) ;
  1090.     DrawHand ( hPS, aptlMinute, 5, DateTime.minutes, &Data->wi ) ;
  1091.     if ( ( Data->wi.cxClient > 50 ) AND ( Data->wi.cyClient > 50 ) )
  1092.     {
  1093.       DrawHand ( hPS, aptlSecond, 2, DateTime.seconds, &Data->wi ) ;
  1094.     }
  1095.   }
  1096.  
  1097.  /***************************************************************************
  1098.   * Else if digital . . .                                                   *
  1099.   ***************************************************************************/
  1100.  
  1101.   else
  1102.   {
  1103.  
  1104.    /*************************************************************************
  1105.     * If minute has changed . . .                                           *
  1106.     *************************************************************************/
  1107.  
  1108.     if ( DateTime.minutes != Data->PreviousDateTime.minutes )
  1109.     {
  1110.       PaintDigitalTime ( hwnd, hPS, Data, &DateTime ) ;
  1111.     }
  1112.   }
  1113.  
  1114.  /***************************************************************************
  1115.   * Adjust the border color to suit the current alert level.                *
  1116.   ***************************************************************************/
  1117.  
  1118.   PaintBorder ( hwnd, hPS, Data, FALSE ) ;
  1119.  
  1120.  /***************************************************************************
  1121.   * Release presentation space.                                             *
  1122.   ***************************************************************************/
  1123.  
  1124.   WinReleasePS ( hPS ) ;
  1125.  
  1126.  /***************************************************************************
  1127.   * Chime if we've passed the top of the hour.  Save time when done.        *
  1128.   ***************************************************************************/
  1129.  
  1130.   if ( Data->IniData.Chime AND ( DateTime.hours != Data->PreviousDateTime.hours ) )
  1131.   {
  1132.     DosBeep  ( 400, 100 ) ;
  1133.     DosSleep (      100 ) ;
  1134.     DosBeep  ( 400, 100 ) ;
  1135.   }
  1136.  
  1137.   Data->PreviousDateTime = DateTime ;
  1138.   Data->PreviousHour = Hour ;
  1139.  
  1140.   return ( 0 ) ;
  1141. }
  1142.  
  1143. /****************************************************************************
  1144.  *                                                                          *
  1145.  *      Repaint entire window.                                              *
  1146.  *                                                                          *
  1147.  ****************************************************************************/
  1148.  
  1149. static MRESULT APIENTRY Paint
  1150. (
  1151.   HWND hwnd,
  1152.   ULONG msg,
  1153.   MPARAM mp1,
  1154.   MPARAM mp2
  1155. )
  1156. {
  1157.  /***************************************************************************
  1158.   *                             Declarations                                *
  1159.   ***************************************************************************/
  1160.  
  1161.   static POINTL
  1162.     aptlHour[5]   = { 0,-15,  10,0,  0,60,  -10,0,  0,-15 },
  1163.     aptlMinute[5] = { 0,-20,   5,0,  0,80,   -5,0,  0,-20 },
  1164.     aptlSecond[2] = { 0,  0,   0,80 } ;
  1165.  
  1166.  /***************************************************************************
  1167.   * Find the instance data.                                                 *
  1168.   ***************************************************************************/
  1169.  
  1170.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1171.  
  1172.  /***************************************************************************
  1173.   * Get presentation space and make it use RGB colors.                      *
  1174.   ***************************************************************************/
  1175.  
  1176.   HPS hPS = WinBeginPaint ( hwnd, HPS(NULL), PRECTL(NULL) ) ;
  1177.   GpiCreateLogColorTable ( hPS, LCOL_RESET, LCOLF_RGB, 0L, 0L, PLONG(NULL) ) ;
  1178.  
  1179.  /***************************************************************************
  1180.   * Paint the background.                                                   *
  1181.   ***************************************************************************/
  1182.  
  1183.   PaintBackground ( hwnd, hPS, Data, TRUE ) ;
  1184.  
  1185.  /***************************************************************************
  1186.   * If analog or minimized . . .                                            *
  1187.   ***************************************************************************/
  1188.  
  1189.   if ( Data->IniData.Analog OR ( Data->IniData.Position.fl & SWP_MINIMIZE ) )
  1190.   {
  1191.  
  1192.    /*************************************************************************
  1193.     * Draw hour, minute and second hands.                                   *
  1194.     *************************************************************************/
  1195.  
  1196.     DrawHand ( hPS, aptlHour,   5, Data->PreviousHour,             &Data->wi ) ;
  1197.     DrawHand ( hPS, aptlMinute, 5, Data->PreviousDateTime.minutes, &Data->wi ) ;
  1198.  
  1199.     if ( ( Data->wi.cxClient > 50 ) AND ( Data->wi.cyClient > 50 ) )
  1200.     {
  1201.       DrawHand ( hPS, aptlSecond, 2, Data->PreviousDateTime.seconds, &Data->wi ) ;
  1202.     }
  1203.   }
  1204.  
  1205.  /***************************************************************************
  1206.   * Else if digital . . .                                                   *
  1207.   ***************************************************************************/
  1208.  
  1209.   else
  1210.   {
  1211.     PaintDigitalTime ( hwnd, hPS, Data, &Data->PreviousDateTime ) ;
  1212.   }
  1213.  
  1214.  /***************************************************************************
  1215.   * Release presentation space and return.                                  *
  1216.   ***************************************************************************/
  1217.  
  1218.   WinEndPaint ( hPS ) ;
  1219.  
  1220.   return ( 0 ) ;
  1221. }
  1222.  
  1223. /****************************************************************************
  1224.  *                                                                          *
  1225.  *      Process commands received by Main Window                            *
  1226.  *                                                                          *
  1227.  ****************************************************************************/
  1228.  
  1229. static MRESULT APIENTRY Command
  1230. (
  1231.   HWND hwnd,
  1232.   ULONG msg,
  1233.   MPARAM mp1,
  1234.   MPARAM mp2
  1235. )
  1236. {
  1237.  /***************************************************************************
  1238.   * Dispatch the messages.  There is no default message processor.          *
  1239.   ***************************************************************************/
  1240.  
  1241.   static METHOD Methods [] =
  1242.   {
  1243.     { IDM_SAVE_APPLICATION, SaveApplication },
  1244.     { IDM_RESET_DEFAULTS,   ResetDefaults   },
  1245.     { IDM_HIDE_CONTROLS,    HideControlsCmd },
  1246.     { IDM_CONFIGURE,        Configure       },
  1247.     { IDM_EXIT,             Exit            },
  1248.     { IDM_ABOUT,            About           }
  1249.   } ;
  1250.  
  1251.   return ( DispatchMessage ( hwnd, SHORT1FROMMP(mp1), mp1, mp2, Methods, sizeof(Methods)/sizeof(Methods[0]), 0 ) ) ;
  1252. }
  1253.  
  1254. /****************************************************************************
  1255.  *                                                                          *
  1256.  *      Process Reset Defaults menu command.                                *
  1257.  *                                                                          *
  1258.  ****************************************************************************/
  1259.  
  1260. static MRESULT APIENTRY ResetDefaults
  1261.   HWND hwnd, 
  1262.   ULONG msg, 
  1263.   MPARAM mp1, 
  1264.   MPARAM mp2
  1265. )
  1266. {
  1267.  /***************************************************************************
  1268.   * Find the instance data.                                                 *
  1269.   ***************************************************************************/
  1270.  
  1271.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1272.  
  1273.  /***************************************************************************
  1274.   * Reset all profile data for this program.                                *
  1275.   ***************************************************************************/
  1276.  
  1277.   PrfWriteProfileData ( Data->IniFile->QueryHandle(), PSZ(PROGRAM_NAME), PSZ(NULL), PSZ(NULL), 0 ) ;
  1278.  
  1279.  /***************************************************************************
  1280.   * Reset the program's presentation parameters.                            *
  1281.   ***************************************************************************/
  1282.  
  1283.   WinRemovePresParam ( hwnd, PP_FONTNAMESIZE ) ;
  1284.   WinRemovePresParam ( hwnd, PP_FOREGROUNDCOLOR ) ;
  1285.   WinRemovePresParam ( hwnd, PP_BACKGROUNDCOLOR ) ;
  1286.  
  1287.  /***************************************************************************
  1288.   * Done.                                                                   *
  1289.   ***************************************************************************/
  1290.  
  1291.   return ( MRFROMSHORT ( 0 ) ) ;
  1292. }
  1293.  
  1294. /****************************************************************************
  1295.  *                                                                          *
  1296.  *      Process Hide Controls menu command.                                 *
  1297.  *                                                                          *
  1298.  ****************************************************************************/
  1299.  
  1300. static MRESULT APIENTRY HideControlsCmd
  1301.   HWND hwnd, 
  1302.   ULONG msg, 
  1303.   MPARAM mp1, 
  1304.   MPARAM mp2
  1305. )
  1306. {
  1307.  /***************************************************************************
  1308.   * Find the instance data.                                                 *
  1309.   ***************************************************************************/
  1310.  
  1311.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1312.  
  1313.  /***************************************************************************
  1314.   * Get the frame window handle.                                            *
  1315.   ***************************************************************************/
  1316.  
  1317.   HWND FrameWindow = WinQueryWindow ( hwnd, QW_PARENT ) ;
  1318.  
  1319.  /***************************************************************************
  1320.   * Toggle the Hide Controls setting.                                       *
  1321.   ***************************************************************************/
  1322.  
  1323.   Data->IniData.HideControls = Data->IniData.HideControls ? FALSE : TRUE ;
  1324.   Data->IniData.fHideControls = TRUE ;
  1325.  
  1326.  /***************************************************************************
  1327.   * If controls aren't hidden yet, update the menu check-mark.              *
  1328.   ***************************************************************************/
  1329.  
  1330.   if ( Data->IniData.HideControls )
  1331.     CheckMenuItem ( FrameWindow, FID_SYSMENU, IDM_HIDE_CONTROLS, Data->IniData.HideControls ) ;
  1332.  
  1333.  /***************************************************************************
  1334.   * If not minimized right now, hide or reveal the controls.                *
  1335.   ***************************************************************************/
  1336.  
  1337.   if ( NOT ( Data->IniData.Position.fl & SWP_MINIMIZE ) )
  1338.   {
  1339.     HideControls
  1340.     (
  1341.       Data->IniData.HideControls,
  1342.       FrameWindow,
  1343.       Data->hwndSysMenu,
  1344.       Data->hwndTitleBar,
  1345.       Data->hwndMinMax
  1346.     ) ;
  1347.   }
  1348.  
  1349.  /***************************************************************************
  1350.   * If controls are no longer hidden, update the menu check-mark.           *
  1351.   ***************************************************************************/
  1352.  
  1353.   if ( NOT Data->IniData.HideControls )
  1354.     CheckMenuItem ( FrameWindow, FID_SYSMENU, IDM_HIDE_CONTROLS, Data->IniData.HideControls ) ;
  1355.  
  1356.  /***************************************************************************
  1357.   * Done.                                                                   *
  1358.   ***************************************************************************/
  1359.  
  1360.   return ( MRFROMSHORT ( 0 ) ) ;
  1361. }
  1362.  
  1363. /****************************************************************************
  1364.  *                                                                          *
  1365.  *      Process Configure command.                                          *
  1366.  *                                                                          *
  1367.  ****************************************************************************/
  1368.  
  1369. static MRESULT APIENTRY Configure
  1370.   HWND hwnd, 
  1371.   ULONG msg, 
  1372.   MPARAM mp1, 
  1373.   MPARAM mp2
  1374. )
  1375. {
  1376.  /***************************************************************************
  1377.   * Find the instance data.                                                 *
  1378.   ***************************************************************************/
  1379.  
  1380.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1381.  
  1382.  /***************************************************************************
  1383.   * Invoke the Configure dialog.                                            *
  1384.   ***************************************************************************/
  1385.  
  1386.   CONFIG_PARMS Parms ;
  1387.   Parms.id           = IDD_CONFIGURE ;
  1388.   Parms.hwndHelp     = WinQueryHelpInstance ( hwnd ) ;
  1389.   Parms.Analog       = Data->IniData.Analog ;
  1390.   Parms.Hour24       = Data->IniData.Hour24 ;
  1391.   Parms.HideControls = Data->IniData.HideControls ;
  1392.   Parms.Chime        = Data->IniData.Chime ;
  1393.   Parms.Float        = Data->IniData.Float ;
  1394.   Parms.Animate      = Data->IniData.Animate ;
  1395.   Parms.AlertType    = Data->IniData.AlertType ;
  1396.  
  1397.   memcpy ( Parms.AlertLevels, Data->IniData.AlertLevels, sizeof(Parms.AlertLevels) ) ;
  1398.  
  1399.   if ( WinDlgBox ( HWND_DESKTOP, hwnd, ConfigureProcessor,
  1400.     Data->Library->QueryHandle(), IDD_CONFIGURE, &Parms ) )
  1401.   {
  1402.     Data->IniData.fHour24 = TRUE ;
  1403.     if ( Data->IniData.Hour24 != Parms.Hour24 )
  1404.     {
  1405.       Data->IniData.Hour24 = Parms.Hour24 ;
  1406.       WinInvalidateRect ( hwnd, PRECTL(NULL), FALSE ) ;
  1407.     }
  1408.  
  1409.     Data->IniData.fChime = TRUE ;
  1410.     Data->IniData.Chime = Parms.Chime ;
  1411.  
  1412.     Data->IniData.fFloat = TRUE ;
  1413.     Data->IniData.Float = Parms.Float ;
  1414.  
  1415.     Data->IniData.fAnimate = TRUE ;
  1416.     Data->IniData.Animate = Parms.Animate ;
  1417.  
  1418.     Data->IniData.fAlertType = TRUE ;
  1419.     if ( Data->IniData.AlertType != Parms.AlertType )
  1420.     {
  1421.       Data->IniData.AlertType = Parms.AlertType ;
  1422.       if ( Data->IniData.AlertType == ALERT_LOAD )
  1423.         DosResumeThread ( Data->IdleLoopTID ) ;
  1424.       else
  1425.         DosSuspendThread ( Data->IdleLoopTID ) ;
  1426.     }
  1427.  
  1428.     Data->IniData.fAnalog = TRUE ;
  1429.     if ( Data->IniData.Analog != Parms.Analog )
  1430.     {
  1431.       Data->IniData.Analog = Parms.Analog ;
  1432.       WinInvalidateRect ( hwnd, PRECTL(NULL), FALSE ) ;
  1433.     }
  1434.  
  1435.     Data->IniData.fHideControls = TRUE ;
  1436.     if ( Data->IniData.HideControls != Parms.HideControls )
  1437.     {
  1438.       HWND FrameWindow = WinQueryWindow ( hwnd, QW_PARENT ) ;
  1439.       Data->IniData.HideControls = Parms.HideControls ;
  1440.       if ( Data->IniData.HideControls )
  1441.         CheckMenuItem ( FrameWindow, FID_SYSMENU, IDM_HIDE_CONTROLS, Data->IniData.HideControls ) ;
  1442.       if ( NOT ( Data->IniData.Position.fl & SWP_MINIMIZE ) )
  1443.       {
  1444.         HideControls
  1445.         (
  1446.           Data->IniData.HideControls,
  1447.           FrameWindow,
  1448.           Data->hwndSysMenu,
  1449.           Data->hwndTitleBar,
  1450.           Data->hwndMinMax
  1451.         ) ;
  1452.       }
  1453.       if ( NOT Data->IniData.HideControls )
  1454.         CheckMenuItem ( FrameWindow, FID_SYSMENU, IDM_HIDE_CONTROLS, Data->IniData.HideControls ) ;
  1455.     }
  1456.  
  1457.     Data->IniData.fAlertLevels = TRUE ;
  1458.     memcpy ( Data->IniData.AlertLevels, Parms.AlertLevels, sizeof(Parms.AlertLevels) ) ;
  1459.   }
  1460.  
  1461.  /***************************************************************************
  1462.   * Done.                                                                   *
  1463.   ***************************************************************************/
  1464.  
  1465.   return ( MRFROMSHORT ( 0 ) ) ;
  1466. }
  1467.  
  1468. /****************************************************************************
  1469.  *                                                                          *
  1470.  *      Process About menu command.                                         *
  1471.  *                                                                          *
  1472.  ****************************************************************************/
  1473.  
  1474. static MRESULT APIENTRY About
  1475.   HWND hwnd, 
  1476.   ULONG msg, 
  1477.   MPARAM mp1, 
  1478.   MPARAM mp2
  1479. )
  1480. {
  1481.  /***************************************************************************
  1482.   * Find the instance data.                                                 *
  1483.   ***************************************************************************/
  1484.  
  1485.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1486.  
  1487.  /***************************************************************************
  1488.   * Invoke the About dialog.                                                *
  1489.   ***************************************************************************/
  1490.  
  1491.   ABOUT_PARMS Parms ;
  1492.   Parms.id = IDD_ABOUT ;
  1493.   Parms.hwndHelp = WinQueryHelpInstance ( hwnd ) ;
  1494.  
  1495.   WinDlgBox ( HWND_DESKTOP, hwnd, AboutProcessor,
  1496.     Data->Library->QueryHandle(), IDD_ABOUT, &Parms ) ;
  1497.  
  1498.  /***************************************************************************
  1499.   * Done.                                                                   *
  1500.   ***************************************************************************/
  1501.  
  1502.   return ( MRFROMSHORT ( 0 ) ) ;
  1503. }
  1504.  
  1505. /****************************************************************************
  1506.  *                                                                          *
  1507.  *      Process Mouse Button being pressed.                                 *
  1508.  *                                                                          *
  1509.  ****************************************************************************/
  1510.  
  1511. static MRESULT APIENTRY ButtonDown
  1512. (
  1513.   HWND hwnd,
  1514.   ULONG msg,
  1515.   MPARAM mp1,
  1516.   MPARAM mp2
  1517. )
  1518. {
  1519.  /***************************************************************************
  1520.   * Find the instance data.                                                 *
  1521.   ***************************************************************************/
  1522.  
  1523.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1524.  
  1525.  /***************************************************************************
  1526.   * Determine the new window position.                                      *
  1527.   ***************************************************************************/
  1528.  
  1529.   TRACKINFO TrackInfo ;
  1530.   memset ( &TrackInfo, 0, sizeof(TrackInfo) ) ;
  1531.  
  1532.   TrackInfo.cxBorder = 1 ;
  1533.   TrackInfo.cyBorder = 1 ;
  1534.   TrackInfo.cxGrid = 1 ;
  1535.   TrackInfo.cyGrid = 1 ;
  1536.   TrackInfo.cxKeyboard = 8 ;
  1537.   TrackInfo.cyKeyboard = 8 ;
  1538.  
  1539.   HWND FrameWindow = WinQueryWindow ( hwnd, QW_PARENT ) ;
  1540.  
  1541.   SWP Position ;
  1542.   WinQueryWindowPos ( FrameWindow, &Position ) ;
  1543.   TrackInfo.rclTrack.xLeft   = Position.x ;
  1544.   TrackInfo.rclTrack.xRight  = Position.x + Position.cx ;
  1545.   TrackInfo.rclTrack.yBottom = Position.y ;
  1546.   TrackInfo.rclTrack.yTop    = Position.y + Position.cy ;
  1547.  
  1548.   WinQueryWindowPos ( HWND_DESKTOP, &Position ) ;
  1549.   TrackInfo.rclBoundary.xLeft   = Position.x ;
  1550.   TrackInfo.rclBoundary.xRight  = Position.x + Position.cx ;
  1551.   TrackInfo.rclBoundary.yBottom = Position.y ;
  1552.   TrackInfo.rclBoundary.yTop    = Position.y + Position.cy ;
  1553.  
  1554.   TrackInfo.ptlMinTrackSize.x = 0 ;
  1555.   TrackInfo.ptlMinTrackSize.y = 0 ;
  1556.   TrackInfo.ptlMaxTrackSize.x = Position.cx ;
  1557.   TrackInfo.ptlMaxTrackSize.y = Position.cy ;
  1558.  
  1559.   TrackInfo.fs = TF_MOVE | TF_STANDARD | TF_ALLINBOUNDARY ;
  1560.  
  1561.   if ( WinTrackRect ( HWND_DESKTOP, HPS(NULL), &TrackInfo ) )
  1562.   {
  1563.     WinSetWindowPos ( FrameWindow, HWND(NULL),
  1564.       (SHORT) TrackInfo.rclTrack.xLeft,
  1565.       (SHORT) TrackInfo.rclTrack.yBottom,
  1566.       0, 0, SWP_MOVE ) ;
  1567.   }
  1568.  
  1569.  /***************************************************************************
  1570.   * Return through the default processor, letting window activation         *
  1571.   *   and other system functions occur.                                     *
  1572.   ***************************************************************************/
  1573.  
  1574.   return ( WinDefWindowProc ( hwnd, msg, mp1, mp2 ) ) ;
  1575. }
  1576.  
  1577. /****************************************************************************
  1578.  *                                                                          *
  1579.  *      Process Mouse Button having been double-clicked.                    *
  1580.  *                                                                          *
  1581.  ****************************************************************************/
  1582.  
  1583. static MRESULT APIENTRY ButtonDblClick
  1584. (
  1585.   HWND hwnd,
  1586.   ULONG msg,
  1587.   MPARAM mp1,
  1588.   MPARAM mp2
  1589. )
  1590. {
  1591.  /***************************************************************************
  1592.   * Send message to self to stop hiding the controls.                       *
  1593.   ***************************************************************************/
  1594.  
  1595.   WinPostMsg ( hwnd, WM_COMMAND,
  1596.     MPFROM2SHORT ( IDM_HIDE_CONTROLS, 0 ),
  1597.     MPFROM2SHORT ( CMDSRC_OTHER, TRUE ) ) ;
  1598.  
  1599.  /***************************************************************************
  1600.   * Return through the default processor, letting window activation         *
  1601.   *   and other system functions occur.                                     *
  1602.   ***************************************************************************/
  1603.  
  1604.   return ( WinDefWindowProc ( hwnd, msg, mp1, mp2 ) ) ;
  1605. }
  1606.  
  1607. /****************************************************************************
  1608.  *                                                                          *
  1609.  *      Process Presentation Parameter Changed notification.                *
  1610.  *                                                                          *
  1611.  ****************************************************************************/
  1612.  
  1613. static MRESULT APIENTRY PresParamChanged
  1614. (
  1615.   HWND hwnd,
  1616.   ULONG msg,
  1617.   MPARAM mp1,
  1618.   MPARAM mp2
  1619. )
  1620. {
  1621.  /***************************************************************************
  1622.   * Find the instance data.                                                 *
  1623.   ***************************************************************************/
  1624.  
  1625.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1626.  
  1627.  /***************************************************************************
  1628.   * Get the presentation parameter that changed.                            *
  1629.   ***************************************************************************/
  1630.  
  1631.   switch ( LONGFROMMP(mp1) )
  1632.   {
  1633.  
  1634.    /*************************************************************************
  1635.     * If font, note the fact that we now have a font to be saved as         *
  1636.     *   part of the configuration.  Get the font metrics and resize         *
  1637.     *   the window appropriately.                                           *
  1638.     *************************************************************************/
  1639.  
  1640.     case PP_FONTNAMESIZE:
  1641.     {
  1642.       ULONG ppid ;
  1643.       if ( WinQueryPresParam ( hwnd, PP_FONTNAMESIZE, 0, &ppid,
  1644.         sizeof(Data->IniData.FontNameSize), &Data->IniData.FontNameSize,
  1645.         0 ) )
  1646.       {
  1647.         Data->IniData.fFontNameSize = TRUE ;
  1648.       }
  1649.       else
  1650.       {
  1651.         strcpy ( PCHAR(Data->IniData.FontNameSize), "" ) ;
  1652.         Data->IniData.fFontNameSize = FALSE ;
  1653.         PrfWriteProfileData ( Data->IniFile->QueryHandle(), PSZ(PROGRAM_NAME), PSZ("FontNameSize"), NULL, 0 ) ;
  1654.       }
  1655.       WinInvalidateRect ( hwnd, PRECTL(NULL), TRUE ) ;
  1656.       break ;
  1657.     }
  1658.  
  1659.    /*************************************************************************
  1660.     * If background color, note the fact and repaint the window.            *
  1661.     *************************************************************************/
  1662.  
  1663.     case PP_BACKGROUNDCOLOR:
  1664.     {
  1665.       ULONG ppid ;
  1666.       if ( WinQueryPresParam ( hwnd, PP_BACKGROUNDCOLOR, 0, &ppid,
  1667.         sizeof(Data->IniData.BackColor), &Data->IniData.BackColor, 0 ) )
  1668.       {
  1669.         Data->IniData.fBackColor = TRUE ;
  1670.       }
  1671.       else
  1672.       {
  1673.         Data->IniData.BackColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_WINDOW, 0L ) ;
  1674.         Data->IniData.fBackColor = FALSE ;
  1675.         PrfWriteProfileData ( Data->IniFile->QueryHandle(), PSZ(PROGRAM_NAME), PSZ("BackgroundColor"), NULL, 0 ) ;
  1676.       }
  1677.       WinInvalidateRect ( hwnd, PRECTL(NULL), TRUE ) ;
  1678.       break ;
  1679.     }
  1680.  
  1681.    /*************************************************************************
  1682.     * If foreground color, note the fact and repaint the window.            *
  1683.     *************************************************************************/
  1684.  
  1685.     case PP_FOREGROUNDCOLOR:
  1686.     {
  1687.       ULONG ppid ;
  1688.       if ( WinQueryPresParam ( hwnd, PP_FOREGROUNDCOLOR, 0, &ppid,
  1689.         sizeof(Data->IniData.TextColor), &Data->IniData.TextColor, 0 ) )
  1690.       {
  1691.         Data->IniData.fTextColor = TRUE ;
  1692.       }
  1693.       else
  1694.       {
  1695.         Data->IniData.TextColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_OUTPUTTEXT, 0L ) ;
  1696.         Data->IniData.fTextColor = FALSE ;
  1697.         PrfWriteProfileData ( Data->IniFile->QueryHandle(), PSZ(PROGRAM_NAME), PSZ("ForegroundColor"), NULL, 0 ) ;
  1698.       }
  1699.       WinInvalidateRect ( hwnd, PRECTL(NULL), TRUE ) ;
  1700.       break ;
  1701.     }
  1702.   }
  1703.  
  1704.  /***************************************************************************
  1705.   * Return through the default processor, letting window activation         *
  1706.   *   and other system functions occur.                                     *
  1707.   ***************************************************************************/
  1708.  
  1709.   return ( WinDefWindowProc ( hwnd, msg, mp1, mp2 ) ) ;
  1710. }
  1711.  
  1712. /****************************************************************************
  1713.  *                                                                          *
  1714.  *      Process System Color Change notification.                           *
  1715.  *                                                                          *
  1716.  ****************************************************************************/
  1717.  
  1718. static MRESULT APIENTRY SysColorChange
  1719. (
  1720.   HWND hwnd,
  1721.   ULONG msg,
  1722.   MPARAM mp1,
  1723.   MPARAM mp2
  1724. )
  1725. {
  1726.  /***************************************************************************
  1727.   * Find the instance data.                                                 *
  1728.   ***************************************************************************/
  1729.  
  1730.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1731.  
  1732.  /***************************************************************************
  1733.   * If we aren't using custom colors, then query for the new defaults.      *
  1734.   ***************************************************************************/
  1735.  
  1736.   if ( NOT Data->IniData.fBackColor )
  1737.   {
  1738.     Data->IniData.BackColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_WINDOW, 0L ) ;
  1739.   }
  1740.  
  1741.   if ( NOT Data->IniData.fTextColor )
  1742.   {
  1743.     Data->IniData.TextColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_OUTPUTTEXT, 0L ) ;
  1744.   }
  1745.  
  1746.  /***************************************************************************
  1747.   * Return value must be NULL, according to the documentation.              *
  1748.   ***************************************************************************/
  1749.  
  1750.   return ( MRFROMP ( NULL ) ) ;
  1751. }
  1752.  
  1753. /****************************************************************************
  1754.  *                                                                          *
  1755.  *      Process Query for Keys Help resource id.                            *
  1756.  *                                                                          *
  1757.  ****************************************************************************/
  1758.  
  1759. static MRESULT APIENTRY QueryKeysHelp
  1760. (
  1761.   HWND hwnd,
  1762.   ULONG msg,
  1763.   MPARAM mp1,
  1764.   MPARAM mp2
  1765. )
  1766. {
  1767.  /***************************************************************************
  1768.   * Simply return the ID of the Keys Help panel.                            *
  1769.   ***************************************************************************/
  1770.  
  1771.   return ( (MRESULT) IDM_KEYS_HELP ) ;
  1772. }
  1773.  
  1774. /****************************************************************************
  1775.  *                                                                          *
  1776.  *      Process Help Manager Error                                          *
  1777.  *                                                                          *
  1778.  ****************************************************************************/
  1779.  
  1780. static MRESULT APIENTRY HelpError
  1781.   HWND hwnd, 
  1782.   ULONG msg, 
  1783.   MPARAM mp1, 
  1784.   MPARAM mp2
  1785. )
  1786. {
  1787.  /***************************************************************************
  1788.   * Local Declarations                                                      *
  1789.   ***************************************************************************/
  1790.  
  1791.   static struct
  1792.   {
  1793.     ULONG Error ;
  1794.     USHORT StringId ;
  1795.   }
  1796.   HelpErrors [] =
  1797.   {
  1798.     { HMERR_NO_FRAME_WND_IN_CHAIN,     IDS_HMERR_NO_FRAME_WND_IN_CHAIN },
  1799.     { HMERR_INVALID_ASSOC_APP_WND,     IDS_HMERR_INVALID_ASSOC_APP_WND },
  1800.     { HMERR_INVALID_ASSOC_HELP_INST,   IDS_HMERR_INVALID_ASSOC_HELP_IN },
  1801.     { HMERR_INVALID_DESTROY_HELP_INST, IDS_HMERR_INVALID_DESTROY_HELP_ },
  1802.     { HMERR_NO_HELP_INST_IN_CHAIN,     IDS_HMERR_NO_HELP_INST_IN_CHAIN },
  1803.     { HMERR_INVALID_HELP_INSTANCE_HDL, IDS_HMERR_INVALID_HELP_INSTANCE },
  1804.     { HMERR_INVALID_QUERY_APP_WND,     IDS_HMERR_INVALID_QUERY_APP_WND },
  1805.     { HMERR_HELP_INST_CALLED_INVALID,  IDS_HMERR_HELP_INST_CALLED_INVA },
  1806.     { HMERR_HELPTABLE_UNDEFINE,        IDS_HMERR_HELPTABLE_UNDEFINE    },
  1807.     { HMERR_HELP_INSTANCE_UNDEFINE,    IDS_HMERR_HELP_INSTANCE_UNDEFIN },
  1808.     { HMERR_HELPITEM_NOT_FOUND,        IDS_HMERR_HELPITEM_NOT_FOUND    },
  1809.     { HMERR_INVALID_HELPSUBITEM_SIZE,  IDS_HMERR_INVALID_HELPSUBITEM_S },
  1810.     { HMERR_HELPSUBITEM_NOT_FOUND,     IDS_HMERR_HELPSUBITEM_NOT_FOUND },
  1811.     { HMERR_INDEX_NOT_FOUND,           IDS_HMERR_INDEX_NOT_FOUND       },
  1812.     { HMERR_CONTENT_NOT_FOUND,         IDS_HMERR_CONTENT_NOT_FOUND     },
  1813.     { HMERR_OPEN_LIB_FILE,             IDS_HMERR_OPEN_LIB_FILE         },
  1814.     { HMERR_READ_LIB_FILE,             IDS_HMERR_READ_LIB_FILE         },
  1815.     { HMERR_CLOSE_LIB_FILE,            IDS_HMERR_CLOSE_LIB_FILE        },
  1816.     { HMERR_INVALID_LIB_FILE,          IDS_HMERR_INVALID_LIB_FILE      },
  1817.     { HMERR_NO_MEMORY,                 IDS_HMERR_NO_MEMORY             },
  1818.     { HMERR_ALLOCATE_SEGMENT,          IDS_HMERR_ALLOCATE_SEGMENT      },
  1819.     { HMERR_FREE_MEMORY,               IDS_HMERR_FREE_MEMORY           },
  1820.     { HMERR_PANEL_NOT_FOUND,           IDS_HMERR_PANEL_NOT_FOUND       },
  1821.     { HMERR_DATABASE_NOT_OPEN,         IDS_HMERR_DATABASE_NOT_OPEN     },
  1822.     { 0,                               IDS_HMERR_UNKNOWN               }
  1823.   } ;
  1824.  
  1825.   ULONG ErrorCode = (ULONG) LONGFROMMP ( mp1 ) ;
  1826.  
  1827.  /***************************************************************************
  1828.   * Find the instance data.                                                 *
  1829.   ***************************************************************************/
  1830.  
  1831.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1832.  
  1833.  /***************************************************************************
  1834.   * Find the error code in the message table.                               *
  1835.   ***************************************************************************/
  1836.  
  1837.   int Index = 0 ;
  1838.   while ( HelpErrors[Index].Error
  1839.     AND ( HelpErrors[Index].Error != ErrorCode ) )
  1840.   {
  1841.     Index ++ ;
  1842.   }
  1843.  
  1844.  /***************************************************************************
  1845.   * Get the message texts.                                                  *
  1846.   ***************************************************************************/
  1847.  
  1848.   ResourceString Title ( Data->Library->QueryHandle(), IDS_HMERR ) ;
  1849.  
  1850.   ResourceString Message ( Data->Library->QueryHandle(), HelpErrors[Index].StringId ) ;
  1851.  
  1852.  /***************************************************************************
  1853.   * Display the error message.                                              *
  1854.   ***************************************************************************/
  1855.  
  1856.   WinMessageBox
  1857.   (
  1858.     HWND_DESKTOP,
  1859.     hwnd,
  1860.     PSZ(Message),
  1861.     PSZ(Title),
  1862.     0,
  1863.     MB_OK | MB_WARNING
  1864.   ) ;
  1865.  
  1866.  /***************************************************************************
  1867.   * Return zero, indicating that the message was processed.                 *
  1868.   ***************************************************************************/
  1869.  
  1870.   return ( MRFROMSHORT ( 0 ) ) ;
  1871. }
  1872.  
  1873. /****************************************************************************
  1874.  *                                                                          *
  1875.  *      Process "Extended Help Undefined" notification                      *
  1876.  *                                                                          *
  1877.  ****************************************************************************/
  1878.  
  1879. static MRESULT APIENTRY ExtHelpUndefined
  1880.   HWND hwnd, 
  1881.   ULONG msg, 
  1882.   MPARAM mp1, 
  1883.   MPARAM mp2
  1884. )
  1885. {
  1886.  /***************************************************************************
  1887.   * Find the instance data.                                                 *
  1888.   ***************************************************************************/
  1889.  
  1890.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1891.  
  1892.  /***************************************************************************
  1893.   * Get the message texts.                                                  *
  1894.   ***************************************************************************/
  1895.  
  1896.   ResourceString Title ( Data->Library->QueryHandle(), IDS_HMERR ) ;
  1897.  
  1898.   ResourceString Message ( Data->Library->QueryHandle(), IDS_HMERR_EXTHELPUNDEFINED ) ;
  1899.  
  1900.  /***************************************************************************
  1901.   * Display the error message.                                              *
  1902.   ***************************************************************************/
  1903.  
  1904.   WinMessageBox
  1905.   (
  1906.     HWND_DESKTOP,
  1907.     hwnd,
  1908.     PSZ(Message),
  1909.     PSZ(Title),
  1910.     0,
  1911.     MB_OK | MB_WARNING
  1912.   ) ;
  1913.  
  1914.  /***************************************************************************
  1915.   * Return zero, indicating that the message was processed.                 *
  1916.   ***************************************************************************/
  1917.  
  1918.   return ( MRFROMSHORT ( 0 ) ) ;
  1919. }
  1920.  
  1921. /****************************************************************************
  1922.  *                                                                          *
  1923.  *      Process "Help Subitem Not Found" notification                       *
  1924.  *                                                                          *
  1925.  ****************************************************************************/
  1926.  
  1927. static MRESULT APIENTRY HelpSubitemNotFound
  1928.   HWND hwnd, 
  1929.   ULONG msg, 
  1930.   MPARAM mp1, 
  1931.   MPARAM mp2
  1932. )
  1933. {
  1934.  /***************************************************************************
  1935.   * Find the instance data.                                                 *
  1936.   ***************************************************************************/
  1937.  
  1938.   PDATA Data = (PDATA) WinQueryWindowPtr ( hwnd, QWL_USER ) ;
  1939.  
  1940.  /***************************************************************************
  1941.   * Get the title text.                                                     *
  1942.   ***************************************************************************/
  1943.  
  1944.   ResourceString Title ( Data->Library->QueryHandle(), IDS_HMERR ) ;
  1945.  
  1946.  /***************************************************************************
  1947.   * Format the error message.                                               *
  1948.   ***************************************************************************/
  1949.  
  1950.   USHORT Topic = (USHORT) SHORT1FROMMP ( mp2 ) ;
  1951.   USHORT Subtopic = (USHORT) SHORT2FROMMP ( mp2 ) ;
  1952.  
  1953.   ResourceString Frame   ( Data->Library->QueryHandle(), IDS_HELPMODE_FRAME ) ;
  1954.   ResourceString Menu    ( Data->Library->QueryHandle(), IDS_HELPMODE_MENU ) ;
  1955.   ResourceString Window  ( Data->Library->QueryHandle(), IDS_HELPMODE_WINDOW ) ;
  1956.   ResourceString Unknown ( Data->Library->QueryHandle(), IDS_HELPMODE_UNKNOWN ) ;
  1957.  
  1958.   PBYTE Mode ;
  1959.   switch ( SHORT1FROMMP ( mp1 ) )
  1960.   {
  1961.     case HLPM_FRAME:
  1962.       Mode = PSZ(Frame) ;
  1963.       break ;
  1964.  
  1965.     case HLPM_MENU:
  1966.       Mode = PSZ(Menu) ;
  1967.       break ;
  1968.  
  1969.     case HLPM_WINDOW:
  1970.       Mode = PSZ(Window) ;
  1971.       break ;
  1972.  
  1973.     default:
  1974.       Mode = PSZ(Unknown) ;
  1975.   }
  1976.  
  1977.   ResourceString Format ( Data->Library->QueryHandle(), IDS_HELPSUBITEMNOTFOUND ) ;
  1978.  
  1979.   BYTE Message [200] ;
  1980.   sprintf ( PCHAR(Message), PCHAR(Format), Mode, Topic, Subtopic ) ;
  1981.  
  1982.  /***************************************************************************
  1983.   * Display the error message.                                              *
  1984.   ***************************************************************************/
  1985.  
  1986.   WinMessageBox
  1987.   (
  1988.     HWND_DESKTOP,
  1989.     hwnd,
  1990.     Message,
  1991.     PSZ(Title),
  1992.     0,
  1993.     MB_OK | MB_WARNING
  1994.   ) ;
  1995.  
  1996.  /***************************************************************************
  1997.   * Return zero, indicating that the message was processed.                 *
  1998.   ***************************************************************************/
  1999.  
  2000.   return ( MRFROMSHORT ( 0 ) ) ;
  2001. }
  2002.  
  2003.  
  2004. /****************************************************************************
  2005.  *                                                                          *
  2006.  *                           Get Profile Data                               *
  2007.  *                                                                          *
  2008.  ****************************************************************************/
  2009.  
  2010. static int GetIniData ( HINI IniHandle, PINIDATA IniData )
  2011. {
  2012.  /***************************************************************************
  2013.   * Get the window's current size and position.                             *
  2014.   ***************************************************************************/
  2015.  
  2016.   #pragma pack(2)
  2017.   typedef struct {
  2018.     USHORT Filler ;
  2019.     USHORT fs ;
  2020.     USHORT cy, cx, y, x ;
  2021.     HWND hwndInsertBehind ;
  2022.     HWND hwnd ;
  2023.   } OLDSWP ;
  2024.   #pragma pack()
  2025.  
  2026.   ULONG Size ;
  2027.   memset ( &IniData->Position, 0, sizeof(IniData->Position) ) ;
  2028.   IniData->fPosition = FALSE ;
  2029.   if ( PrfQueryProfileSize ( IniHandle, PSZ(PROGRAM_NAME), PSZ("Position"), &Size ) )
  2030.   {
  2031.     if ( Size == sizeof(OLDSWP)-sizeof(USHORT) )
  2032.     {
  2033.       OLDSWP OldPosition ;
  2034.       if ( PrfQueryProfileData ( IniHandle, PSZ(PROGRAM_NAME), PSZ("Position"), &OldPosition.fs, &Size ) )
  2035.       {
  2036.         IniData->Position.fl = OldPosition.fs ;
  2037.         IniData->Position.cy = OldPosition.cy ;
  2038.         IniData->Position.cx = OldPosition.cx ;
  2039.         IniData->Position.y = OldPosition.y ;
  2040.         IniData->Position.x = OldPosition.x ;
  2041.         IniData->Position.hwndInsertBehind = OldPosition.hwndInsertBehind ;
  2042.         IniData->Position.hwnd = OldPosition.hwnd ;
  2043.         IniData->fPosition = TRUE ;
  2044.       }
  2045.     }
  2046.     else if ( Size == sizeof(IniData->Position) )
  2047.     {
  2048.       if ( PrfQueryProfileData ( IniHandle, PSZ(PROGRAM_NAME), PSZ("Position"), &IniData->Position, &Size ) )
  2049.       {
  2050.         IniData->fPosition = TRUE ;
  2051.       }
  2052.     }
  2053.   }
  2054.  
  2055.   if ( NOT IniData->fPosition )
  2056.   {
  2057.     if ( IniHandle == HINI_USERPROFILE )
  2058.     {
  2059.       return ( 1 ) ;
  2060.     }
  2061.   }
  2062.  
  2063.  /***************************************************************************
  2064.   * Get the program options.                                                *
  2065.   ***************************************************************************/
  2066.  
  2067.   IniData->Hour24 = FALSE ;
  2068.   if
  2069.   (
  2070.     PrfQueryProfileSize ( IniHandle, PSZ(PROGRAM_NAME), PSZ("Hour24"), &Size )
  2071.     AND
  2072.     ( ( Size == sizeof(IniData->Hour24) ) OR ( Size == sizeof(SHORT) ) )
  2073.     AND
  2074.     PrfQueryProfileData ( IniHandle, PSZ(PROGRAM_NAME), PSZ("Hour24"), &IniData->Hour24, &Size )
  2075.   )
  2076.   {
  2077.     IniData->fHour24 = TRUE ;
  2078.   }
  2079.  
  2080.   IniData->HideControls = FALSE ;
  2081.   if
  2082.   (
  2083.     PrfQueryProfileSize ( IniHandle, PSZ(PROGRAM_NAME), PSZ("HideControls"), &Size )
  2084.     AND
  2085.     ( ( Size == sizeof(IniData->HideControls) ) OR ( Size == sizeof(SHORT) ) )
  2086.     AND
  2087.     PrfQueryProfileData ( IniHandle, PSZ(PROGRAM_NAME), PSZ("HideControls"), &IniData->HideControls, &Size )
  2088.   )
  2089.   {
  2090.     IniData->fHideControls = TRUE ;
  2091.   }
  2092.  
  2093.   IniData->Chime = FALSE ;
  2094.   if
  2095.   (
  2096.     PrfQueryProfileSize ( IniHandle, PSZ(PROGRAM_NAME), PSZ("Chime"), &Size )
  2097.     AND
  2098.     ( ( Size == sizeof(IniData->Chime) ) OR ( Size == sizeof(SHORT) ) )
  2099.     AND
  2100.     PrfQueryProfileData ( IniHandle, PSZ(PROGRAM_NAME), PSZ("Chime"), &IniData->Chime, &Size )
  2101.   )
  2102.   {
  2103.     IniData->fChime = TRUE ;
  2104.   }
  2105.  
  2106.   IniData->Float = FALSE ;
  2107.   if
  2108.   (
  2109.     PrfQueryProfileSize ( IniHandle, PSZ(PROGRAM_NAME), PSZ("Float"), &Size )
  2110.     AND
  2111.     ( ( Size == sizeof(IniData->Float) ) OR ( Size == sizeof(SHORT) ) )
  2112.     AND
  2113.     PrfQueryProfileData ( IniHandle, PSZ(PROGRAM_NAME), PSZ("Float"), &IniData->Float, &Size )
  2114.   )
  2115.   {
  2116.     IniData->fFloat = TRUE ;
  2117.   }
  2118.  
  2119.   IniData->Animate = FALSE ;
  2120.   if
  2121.   (
  2122.     PrfQueryProfileSize ( IniHandle, PSZ(PROGRAM_NAME), PSZ("Animate"), &Size )
  2123.     AND
  2124.     ( ( Size == sizeof(IniData->Animate) ) OR ( Size == sizeof(SHORT) ) )
  2125.     AND
  2126.     PrfQueryProfileData ( IniHandle, PSZ(PROGRAM_NAME), PSZ("Animate"), &IniData->Animate, &Size )
  2127.   )
  2128.   {
  2129.     IniData->fAnimate = TRUE ;
  2130.   }
  2131.  
  2132.   IniData->Analog = TRUE ;
  2133.   if
  2134.   (
  2135.     PrfQueryProfileSize ( IniHandle, PSZ(PROGRAM_NAME), PSZ("Analog"), &Size )
  2136.     AND
  2137.     ( ( Size == sizeof(IniData->Analog) ) OR ( Size == sizeof(SHORT) ) )
  2138.     AND
  2139.     PrfQueryProfileData ( IniHandle, PSZ(PROGRAM_NAME), PSZ("Analog"), &IniData->Analog, &Size )
  2140.   )
  2141.   {
  2142.     IniData->fAnalog = TRUE ;
  2143.   }
  2144.  
  2145.   IniData->AlertType = ALERT_TASKCOUNT ;
  2146.   if
  2147.   (
  2148.     PrfQueryProfileSize ( IniHandle, PSZ(PROGRAM_NAME), PSZ("AlertType"), &Size )
  2149.     AND
  2150.     ( ( Size == sizeof(IniData->AlertType) ) OR ( Size == sizeof(SHORT) ) )
  2151.     AND
  2152.     PrfQueryProfileData ( IniHandle, PSZ(PROGRAM_NAME), PSZ("AlertType"), &IniData->AlertType, &Size )
  2153.   )
  2154.   {
  2155.     IniData->fAlertType = TRUE ;
  2156.   }
  2157.  
  2158.   IniData->AlertLevels [ALERT_TASKCOUNT] [0] = 8 ;
  2159.   IniData->AlertLevels [ALERT_TASKCOUNT] [1] = 12 ;
  2160.   IniData->AlertLevels [ALERT_LOAD]      [0] = 33 ;
  2161.   IniData->AlertLevels [ALERT_LOAD]      [1] = 67 ;
  2162.  
  2163.   if
  2164.   (
  2165.     PrfQueryProfileSize ( IniHandle, PSZ(PROGRAM_NAME), PSZ("AlertLevels"), &Size )
  2166.     AND
  2167.     ( Size == sizeof(IniData->AlertLevels) )
  2168.     AND
  2169.     PrfQueryProfileData ( IniHandle, PSZ(PROGRAM_NAME), PSZ("AlertLevels"), IniData->AlertLevels, &Size )
  2170.   )
  2171.   {
  2172.     IniData->fAlertLevels = TRUE ;
  2173.   }
  2174.  
  2175.  /***************************************************************************
  2176.   * Get the presentation parameters.                                        *
  2177.   ***************************************************************************/
  2178.  
  2179.   strcpy ( PCHAR(IniData->FontNameSize), "" ) ;
  2180.   IniData->fFontNameSize = FALSE ;
  2181.   if
  2182.   (
  2183.     PrfQueryProfileSize ( IniHandle, PSZ(PROGRAM_NAME), PSZ("FontNameSize"), &Size )
  2184.     AND
  2185.     ( Size == sizeof(IniData->FontNameSize) )
  2186.     AND
  2187.     PrfQueryProfileData ( IniHandle, PSZ(PROGRAM_NAME), PSZ("FontNameSize"), &IniData->FontNameSize, &Size )
  2188.   )
  2189.   {
  2190.     IniData->fFontNameSize = TRUE ;
  2191.   }
  2192.  
  2193.   IniData->BackColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_WINDOW, 0L ) ;
  2194.   IniData->fBackColor = FALSE ;
  2195.   if
  2196.   (
  2197.     PrfQueryProfileSize ( IniHandle, PSZ(PROGRAM_NAME), PSZ("BackgroundColor"), &Size )
  2198.     AND
  2199.     ( Size == sizeof(IniData->BackColor) )
  2200.     AND
  2201.     PrfQueryProfileData ( IniHandle, PSZ(PROGRAM_NAME), PSZ("BackgroundColor"), &IniData->BackColor, &Size )
  2202.   )
  2203.   {
  2204.     IniData->fBackColor = TRUE ;
  2205.   }
  2206.  
  2207.   IniData->TextColor = WinQuerySysColor ( HWND_DESKTOP, SYSCLR_OUTPUTTEXT, 0L ) ;
  2208.   IniData->fTextColor = FALSE ;
  2209.   if
  2210.   (
  2211.     PrfQueryProfileSize ( IniHandle, PSZ(PROGRAM_NAME), PSZ("ForegroundColor"), &Size )
  2212.     AND
  2213.     ( Size == sizeof(IniData->TextColor) )
  2214.     AND
  2215.     PrfQueryProfileData ( IniHandle, PSZ(PROGRAM_NAME), PSZ("ForegroundColor"), &IniData->TextColor, &Size )
  2216.   )
  2217.   {
  2218.     IniData->fTextColor = TRUE ;
  2219.   }
  2220.  
  2221.  /***************************************************************************
  2222.   * Return no error.                                                        *
  2223.   ***************************************************************************/
  2224.  
  2225.   return ( 0 ) ;
  2226. }
  2227.  
  2228. /****************************************************************************
  2229.  *                                                                          *
  2230.  *                           Put Profile Data                               *
  2231.  *                                                                          *
  2232.  ****************************************************************************/
  2233.  
  2234. static VOID PutIniData ( HINI IniHandle, PINIDATA IniData )
  2235. {
  2236.  /***************************************************************************
  2237.   * Save the window's current size and position.                            *
  2238.   ***************************************************************************/
  2239.  
  2240.   PrfWriteProfileData
  2241.   (
  2242.     IniHandle,
  2243.     PSZ(PROGRAM_NAME),
  2244.     PSZ("Position"),
  2245.     &IniData->Position,
  2246.     sizeof(IniData->Position)
  2247.   ) ;
  2248.  
  2249.  /***************************************************************************
  2250.   * Save the program options.                                               *
  2251.   ***************************************************************************/
  2252.  
  2253.   if ( IniData->fHour24 )
  2254.   {
  2255.     PrfWriteProfileData
  2256.     (
  2257.       IniHandle,
  2258.       PSZ(PROGRAM_NAME),
  2259.       PSZ("Hour24"),
  2260.       &IniData->Hour24,
  2261.       (ULONG)sizeof(IniData->Hour24)
  2262.     ) ;
  2263.   }
  2264.  
  2265.   if ( IniData->fHideControls )
  2266.   {
  2267.     PrfWriteProfileData
  2268.     (
  2269.       IniHandle,
  2270.       PSZ(PROGRAM_NAME),
  2271.       PSZ("HideControls"),
  2272.       &IniData->HideControls,
  2273.       (ULONG)sizeof(IniData->HideControls)
  2274.     ) ;
  2275.   }
  2276.  
  2277.   if ( IniData->fChime )
  2278.   {
  2279.     PrfWriteProfileData
  2280.     (
  2281.       IniHandle,
  2282.       PSZ(PROGRAM_NAME),
  2283.       PSZ("Chime"),
  2284.       &IniData->Chime,
  2285.       (ULONG)sizeof(IniData->Chime)
  2286.     ) ;
  2287.   }
  2288.  
  2289.   if ( IniData->fFloat )
  2290.   {
  2291.     PrfWriteProfileData
  2292.     (
  2293.       IniHandle,
  2294.       PSZ(PROGRAM_NAME),
  2295.       PSZ("Float"),
  2296.       &IniData->Float,
  2297.       (ULONG)sizeof(IniData->Float)
  2298.     ) ;
  2299.   }
  2300.  
  2301.   if ( IniData->fAnimate )
  2302.   {
  2303.     PrfWriteProfileData
  2304.     (
  2305.       IniHandle,
  2306.       PSZ(PROGRAM_NAME),
  2307.       PSZ("Animate"),
  2308.       &IniData->Animate,
  2309.       (ULONG)sizeof(IniData->Animate)
  2310.     ) ;
  2311.   }
  2312.  
  2313.   if ( IniData->fAnalog )
  2314.   {
  2315.     PrfWriteProfileData
  2316.     (
  2317.       IniHandle,
  2318.       PSZ(PROGRAM_NAME),
  2319.       PSZ("Analog"),
  2320.       &IniData->Analog,
  2321.       (ULONG)sizeof(IniData->Analog)
  2322.     ) ;
  2323.   }
  2324.  
  2325.   if ( IniData->fAlertType )
  2326.   {
  2327.     PrfWriteProfileData
  2328.     (
  2329.       IniHandle,
  2330.       PSZ(PROGRAM_NAME),
  2331.       PSZ("AlertType"),
  2332.       &IniData->AlertType,
  2333.       (ULONG)sizeof(IniData->AlertType)
  2334.     ) ;
  2335.   }
  2336.  
  2337.   if ( IniData->fAlertLevels )
  2338.   {
  2339.     PrfWriteProfileData
  2340.     (
  2341.       IniHandle,
  2342.       PSZ(PROGRAM_NAME),
  2343.       PSZ("AlertLevels"),
  2344.       IniData->AlertLevels,
  2345.       (ULONG)sizeof(IniData->AlertLevels)
  2346.     ) ;
  2347.   }
  2348.  
  2349.  /***************************************************************************
  2350.   * Save the presentation parameters.                                       *
  2351.   ***************************************************************************/
  2352.  
  2353.   if ( IniData->fFontNameSize )
  2354.   {
  2355.     PrfWriteProfileData
  2356.     (
  2357.       IniHandle,
  2358.       PSZ(PROGRAM_NAME),
  2359.       PSZ("FontNameSize"),
  2360.       IniData->FontNameSize,
  2361.       sizeof(IniData->FontNameSize)
  2362.     ) ;
  2363.   }
  2364.  
  2365.   if ( IniData->fBackColor )
  2366.   {
  2367.     PrfWriteProfileData
  2368.     (
  2369.       IniHandle,
  2370.       PSZ(PROGRAM_NAME),
  2371.       PSZ("BackgroundColor"),
  2372.       &IniData->BackColor,
  2373.       sizeof(IniData->BackColor)
  2374.     ) ;
  2375.   }
  2376.  
  2377.   if ( IniData->fTextColor )
  2378.   {
  2379.     PrfWriteProfileData
  2380.     (
  2381.       IniHandle,
  2382.       PSZ(PROGRAM_NAME),
  2383.       PSZ("ForegroundColor"),
  2384.       &IniData->TextColor,
  2385.       sizeof(IniData->TextColor)
  2386.     ) ;
  2387.   }
  2388. }
  2389.  
  2390. /****************************************************************************
  2391.  *                                                                          *
  2392.  *      Perform point coordinate rotation.                                  *
  2393.  *                                                                          *
  2394.  ****************************************************************************/
  2395.  
  2396. static VOID RotatePoint ( POINTL aptl[],  SHORT sNum, SHORT sAngle )
  2397. {
  2398.   static SHORT sSin[60] = {
  2399.       0,  105,  208,  309,  407,  500,  588,  669,  743,  809,
  2400.     866,  914,  951,  978,  995, 1000,  995,  978,  951,  914,
  2401.     866,  809,  743,  669,  588,  500,  407,  309,  208,  105,
  2402.       0, -104, -207, -308, -406, -499, -587, -668, -742, -808,
  2403.    -865, -913, -950, -977, -994, -999, -994, -977, -950, -913,
  2404.    -865, -808, -742, -668, -587, -499, -406, -308, -207, -104 };
  2405.  
  2406.   POINTL ptlTemp ;
  2407.   SHORT sIndex ;
  2408.  
  2409.   for ( sIndex = 0; sIndex < sNum ; sIndex++ )
  2410.   {
  2411.     ptlTemp.x = (aptl[sIndex].x * sSin[(sAngle+15)%60] +
  2412.       aptl[sIndex].y * sSin[sAngle]) / 1000 ;
  2413.     ptlTemp.y = (aptl[sIndex].y * sSin[(sAngle+15)%60] -
  2414.       aptl[sIndex].x * sSin[sAngle]) / 1000 ;
  2415.     aptl[sIndex] = ptlTemp ;
  2416.   }
  2417. }
  2418.  
  2419. /****************************************************************************
  2420.  *                                                                          *
  2421.  *      Perform point coordinate scaling.                                   *
  2422.  *                                                                          *
  2423.  ****************************************************************************/
  2424.  
  2425. static VOID ScalePoint ( POINTL aptl[], SHORT sNum, PWINDOWINFO pwi )
  2426. {
  2427.   SHORT sIndex ;
  2428.  
  2429.   for ( sIndex=0; sIndex < sNum; sIndex++ )
  2430.   {
  2431.     aptl[sIndex].x = aptl[sIndex].x * pwi->cxPixelDiam / 200 ;
  2432.     aptl[sIndex].y = aptl[sIndex].y * pwi->cyPixelDiam / 200 ;
  2433.   }
  2434. }
  2435.  
  2436. /****************************************************************************
  2437.  *                                                                          *
  2438.  *      Perform point coordinate translation.                               *
  2439.  *                                                                          *
  2440.  ****************************************************************************/
  2441.  
  2442. static VOID TranslatePoint ( POINTL aptl[], SHORT sNum, PWINDOWINFO pwi )
  2443. {
  2444.   SHORT sIndex ;
  2445.  
  2446.   for ( sIndex=0; sIndex<sNum; sIndex++ )
  2447.   {
  2448.     aptl[sIndex].x += pwi->cxClient / 2 - 1 ;
  2449.     aptl[sIndex].y += pwi->cyClient / 2 - 1 ;
  2450.   }
  2451. }
  2452.  
  2453. /****************************************************************************
  2454.  *                                                                          *
  2455.  *      Draw a clock hand.                                                  *
  2456.  *                                                                          *
  2457.  ****************************************************************************/
  2458.  
  2459. static VOID DrawHand ( HPS hPS, POINTL aptlIn[], SHORT sNum, SHORT sAngle,
  2460.   PWINDOWINFO pwi )
  2461. {
  2462.   POINTL aptl[5] ;
  2463.   SHORT sIndex ;
  2464.  
  2465.   for ( sIndex=0; sIndex<sNum; sIndex++ )
  2466.   {
  2467.     aptl [ sIndex ] = aptlIn [ sIndex ] ;
  2468.   }
  2469.  
  2470.   RotatePoint ( aptl, sNum, sAngle ) ;
  2471.   ScalePoint ( aptl, sNum, pwi ) ;
  2472.   TranslatePoint ( aptl, sNum, pwi ) ;
  2473.  
  2474.   GpiMove ( hPS, aptl ) ;
  2475.   GpiPolyLine ( hPS, sNum-1L, aptl+1 ) ;
  2476. }
  2477.  
  2478. /****************************************************************************
  2479.  *                                                                          *
  2480.  *                   Paint Background (all but hands)                       *
  2481.  *                                                                          *
  2482.  ****************************************************************************/
  2483.  
  2484. static void PaintBackground ( HWND hwnd, HPS hPS, PDATA Data, BOOL MustPaint )
  2485. {
  2486.  /***************************************************************************
  2487.   * Local Declarations                                                      *
  2488.   ***************************************************************************/
  2489.  
  2490.   SHORT  Angle ;
  2491.   POINTL Points [3] ;
  2492.   RECTL  Rectangle ;
  2493.  
  2494.  /***************************************************************************
  2495.   * Clear the window.                                                       *
  2496.   ***************************************************************************/
  2497.  
  2498.   WinQueryWindowRect ( hwnd, &Rectangle ) ;
  2499.  
  2500.   GpiMove ( hPS, (PPOINTL) &Rectangle.xLeft ) ;
  2501.   GpiSetColor ( hPS, Data->IniData.BackColor ) ;
  2502.   GpiBox ( hPS, DRO_FILL, (PPOINTL) &Rectangle.xRight, 0L, 0L ) ;
  2503.  
  2504.  /***************************************************************************
  2505.   * Paint the appropriate border color.                                     *
  2506.   ***************************************************************************/
  2507.  
  2508.   PaintBorder ( hwnd, hPS, Data, MustPaint ) ;
  2509.  
  2510.  /***************************************************************************
  2511.   * If analog or minimized . . .                                            *
  2512.   ***************************************************************************/
  2513.  
  2514.   if ( Data->IniData.Analog OR ( Data->IniData.Position.fl & SWP_MINIMIZE ) )
  2515.   {
  2516.  
  2517.    /*************************************************************************
  2518.     * Draw hour and minute marks around the dial.                           *
  2519.     *************************************************************************/
  2520.  
  2521.     GpiSetColor ( hPS, Data->IniData.TextColor ) ;
  2522.  
  2523.     for ( Angle=0; Angle<60; Angle++ )
  2524.     {
  2525.       Points[0].x = 0 ;
  2526.       Points[0].y = 90 ;
  2527.       RotatePoint ( Points, 1, Angle ) ;
  2528.       ScalePoint ( Points, 1, &Data->wi ) ;
  2529.       TranslatePoint ( Points, 1, &Data->wi ) ;
  2530.       Points[2].x = Points[2].y = Angle % 5 ? 2 : 10 ;
  2531.  
  2532.       ScalePoint ( Points + 2, 1, &Data->wi ) ;
  2533.  
  2534.       Points[0].x -= Points[2].x / 2 ;
  2535.       Points[0].y -= Points[2].y / 2 ;
  2536.  
  2537.       Points[1].x = Points[0].x + Points[2].x ;
  2538.       Points[1].y = Points[0].y + Points[2].y ;
  2539.  
  2540.       GpiMove ( hPS, Points ) ;
  2541.  
  2542.       if ( ( Angle % 5 == 0 ) OR
  2543.         ( ( Data->wi.cxClient ) > 50 ) AND ( Data->wi.cyClient > 50 ) )
  2544.       {
  2545.         GpiBox ( hPS, DRO_OUTLINEFILL, Points+1, Points[2].x, Points[2].y ) ;
  2546.       }
  2547.     }
  2548.   }
  2549. }
  2550.  
  2551. /****************************************************************************
  2552.  *                                                                          *
  2553.  *                            Paint Border                                  *
  2554.  *                                                                          *
  2555.  ****************************************************************************/
  2556.  
  2557. static void PaintBorder ( HWND hwnd, HPS hPS, PDATA Data, BOOL MustPaint )
  2558. {
  2559.  /***************************************************************************
  2560.   * Local Declarations                                                      *
  2561.   ***************************************************************************/
  2562.  
  2563.   USHORT Alert ;
  2564.   USHORT Level ;
  2565.   POINTL Point ;
  2566.   RECTL  Rectangle ;
  2567.  
  2568.  /***************************************************************************
  2569.   * Determine level of the current alert type.                              *
  2570.   ***************************************************************************/
  2571.  
  2572.   if ( Data->IniData.AlertType == ALERT_TASKCOUNT )
  2573.   {
  2574.     Level = WinQuerySwitchList ( Data->Proc->QueryAnchor(), PSWBLOCK(NULL), 0 ) ;
  2575.   }
  2576.   else
  2577.   {
  2578.     Data->MaxCount = (ULONG) max ( Data->MaxCount, Data->IdleCount ) ;
  2579.     Level = (USHORT) ( ( ( Data->MaxCount - Data->IdleCount ) * 100 ) / Data->MaxCount ) ;
  2580.   }
  2581.  
  2582.  /***************************************************************************
  2583.   * Determine alert class.                                                  *
  2584.   ***************************************************************************/
  2585.  
  2586.   if ( Level < Data->IniData.AlertLevels[Data->IniData.AlertType][0] )
  2587.     Alert = 0 ;
  2588.   else if ( Level < Data->IniData.AlertLevels[Data->IniData.AlertType][1] )
  2589.     Alert = 1 ;
  2590.   else
  2591.     Alert = 2 ;
  2592.  
  2593.  /***************************************************************************
  2594.   * If border must be painted, or the alert level has changed, paint it.    *
  2595.   ***************************************************************************/
  2596.  
  2597.   if ( MustPaint OR ( Alert != Data->Alert ) )
  2598.   {
  2599.     WinQueryWindowRect ( hwnd, &Rectangle ) ;
  2600.  
  2601.     GpiSetColor ( hPS, Alert > 1 ? RGB_RED : ( Alert > 0 ? RGB_YELLOW : RGB_GREEN ) ) ;
  2602.  
  2603.     Point.x = 0 ;
  2604.     Point.y = 0 ;
  2605.     GpiMove ( hPS, &Point ) ;
  2606.  
  2607.     Point.x = Rectangle.xRight - 1 ;
  2608.     Point.y = Rectangle.yTop - 1 ;
  2609.     GpiBox ( hPS, DRO_OUTLINE, &Point, 0L, 0L ) ;
  2610.  
  2611.     Point.x = 1 ;
  2612.     Point.y = 1 ;
  2613.     GpiMove ( hPS, &Point ) ;
  2614.  
  2615.     Point.x = Rectangle.xRight - 2 ;
  2616.     Point.y = Rectangle.yTop - 2 ;
  2617.     GpiBox ( hPS, DRO_OUTLINE, &Point, 0L, 0L ) ;
  2618.  
  2619.     Data->Alert = Alert ;
  2620.   }
  2621. }
  2622.  
  2623. /****************************************************************************
  2624.  *                                                                          *
  2625.  *                          Paint Digital Time                              *
  2626.  *                                                                          *
  2627.  ****************************************************************************/
  2628.  
  2629. static void PaintDigitalTime ( HWND hwnd, HPS hPS, PDATA Data, PDATETIME DateTime )
  2630. {
  2631.  /***************************************************************************
  2632.   * Local Declarations                                                      *
  2633.   ***************************************************************************/
  2634.  
  2635.   USHORT Hour ;
  2636.   RECTL Rectangle ;
  2637.   CHAR Text [20] ;
  2638.  
  2639.  /***************************************************************************
  2640.   * Determine the window rectangle, less the border.                        *
  2641.   ***************************************************************************/
  2642.  
  2643.   WinQueryWindowRect ( hwnd, &Rectangle ) ;
  2644.  
  2645.   Rectangle.xLeft += 2 ;
  2646.   Rectangle.xRight -= 2 ;
  2647.   Rectangle.yBottom += 2 ;
  2648.   Rectangle.yTop -= 2 ;
  2649.  
  2650.  /***************************************************************************
  2651.   * Draw the new time within the rectangle.                                 *
  2652.   ***************************************************************************/
  2653.  
  2654.   if ( ( DateTime->minutes == 0 ) AND ( DateTime->hours % 12 == 0 ) )
  2655.   {
  2656.     if ( DateTime->hours == 0 )
  2657.     {
  2658.       ResourceString Midnight ( Data->Library->QueryHandle(), IDS_MIDNIGHT ) ;
  2659.       strcpy ( Text, PCHAR(Midnight) ) ;
  2660.     }
  2661.     else if ( DateTime->hours == 12 )
  2662.     {
  2663.       ResourceString Noon ( Data->Library->QueryHandle(), IDS_NOON ) ;
  2664.       strcpy ( Text, PCHAR(Noon) ) ;
  2665.     }
  2666.   }
  2667.   else
  2668.   {
  2669.     if ( Data->IniData.Hour24 )
  2670.     {
  2671.       sprintf ( Text, "%u%s%02u",
  2672.         DateTime->hours, Data->CountryInfo.szTimeSeparator, DateTime->minutes ) ;
  2673.     }
  2674.     else
  2675.     {
  2676.       ResourceString Am ( Data->Library->QueryHandle(), IDS_AM ) ;
  2677.       ResourceString Pm ( Data->Library->QueryHandle(), IDS_PM ) ;
  2678.  
  2679.       Hour = DateTime->hours % 12 ;
  2680.  
  2681.       if ( Hour == 0 )
  2682.         Hour = 12 ;
  2683.  
  2684.       sprintf ( Text, "%u%s%02u%s",
  2685.         Hour, Data->CountryInfo.szTimeSeparator, DateTime->minutes,
  2686.         (DateTime->hours>=12) ? PSZ(Pm) : PSZ(Am) ) ;
  2687.     }
  2688.   }
  2689.  
  2690.   WinDrawText ( hPS, strlen(Text), PSZ(Text), &Rectangle,
  2691.     Data->IniData.TextColor, Data->IniData.BackColor,
  2692.     DT_CENTER | DT_VCENTER | DT_ERASERECT ) ;
  2693. }
  2694.  
  2695. /****************************************************************************
  2696.  *                                                                          *
  2697.  *                      Hide Window Controls                                *
  2698.  *                                                                          *
  2699.  ****************************************************************************/
  2700.  
  2701. static void HideControls
  2702. (
  2703.   BOOL fHide,
  2704.   HWND FrameWindow,
  2705.   HWND hwndSysMenu,
  2706.   HWND hwndTitleBar,
  2707.   HWND hwndMinMax
  2708. )
  2709. {
  2710.  /***************************************************************************
  2711.   * Local Declarations                                                      *
  2712.   ***************************************************************************/
  2713.  
  2714.   SWP OldPosition ;
  2715.   SWP Position ;
  2716.   RECTL Rectangle ;
  2717.  
  2718.  /***************************************************************************
  2719.   * Get original window position and state.                                 *
  2720.   ***************************************************************************/
  2721.  
  2722.   WinQueryWindowPos ( FrameWindow, &OldPosition ) ;
  2723.  
  2724.  /***************************************************************************
  2725.   * Restore and hide the window.                                            *
  2726.   ***************************************************************************/
  2727.  
  2728.   WinSetWindowPos ( FrameWindow, HWND(NULL), 0, 0, 0, 0, SWP_RESTORE | SWP_HIDE ) ;
  2729.  
  2730.  /***************************************************************************
  2731.   * Determine client window and location.                                   *
  2732.   ***************************************************************************/
  2733.  
  2734.   WinQueryWindowPos ( FrameWindow, &Position ) ;
  2735.  
  2736.   Rectangle.xLeft   = Position.x ;
  2737.   Rectangle.xRight  = Position.x + Position.cx ;
  2738.   Rectangle.yBottom = Position.y ;
  2739.   Rectangle.yTop    = Position.y + Position.cy ;
  2740.  
  2741.   WinCalcFrameRect ( FrameWindow, &Rectangle, TRUE ) ;
  2742.  
  2743.  /***************************************************************************
  2744.   * Hide or reveal the controls windows by changing their parentage.        *
  2745.   ***************************************************************************/
  2746.  
  2747.   if ( fHide )
  2748.   {
  2749.     WinSetParent ( hwndSysMenu,  HWND_OBJECT, FALSE ) ;
  2750.     WinSetParent ( hwndTitleBar, HWND_OBJECT, FALSE ) ;
  2751.     WinSetParent ( hwndMinMax,   HWND_OBJECT, FALSE ) ;
  2752.   }
  2753.   else
  2754.   {
  2755.     WinSetParent ( hwndSysMenu,  FrameWindow, TRUE ) ;
  2756.     WinSetParent ( hwndTitleBar, FrameWindow, TRUE ) ;
  2757.     WinSetParent ( hwndMinMax,   FrameWindow, TRUE ) ;
  2758.   }
  2759.  
  2760.  /***************************************************************************
  2761.   * Tell the frame that things have changed.  Let it update the window.     *
  2762.   ***************************************************************************/
  2763.  
  2764.   WinSendMsg ( FrameWindow, WM_UPDATEFRAME,
  2765.     MPFROMSHORT ( FCF_TITLEBAR | FCF_SYSMENU | FCF_MINBUTTON ), 0L ) ;
  2766.  
  2767.  /***************************************************************************
  2768.   * Reposition the frame around the client window, which is left be.        *
  2769.   ***************************************************************************/
  2770.  
  2771.   WinCalcFrameRect ( FrameWindow, &Rectangle, FALSE ) ;
  2772.  
  2773.   WinSetWindowPos ( FrameWindow, HWND(NULL),
  2774.     (SHORT) Rectangle.xLeft,  (SHORT) Rectangle.yBottom,
  2775.     (SHORT) (Rectangle.xRight-Rectangle.xLeft),
  2776.     (SHORT) (Rectangle.yTop-Rectangle.yBottom),
  2777.     SWP_SIZE | SWP_MOVE ) ;
  2778.  
  2779.  /***************************************************************************
  2780.   * If window was maximized, put it back that way.                          *
  2781.   ***************************************************************************/
  2782.  
  2783.   if ( OldPosition.fl & SWP_MAXIMIZE )
  2784.   {
  2785.     WinSetWindowPos ( FrameWindow, HWND(NULL),
  2786.       (SHORT) Rectangle.xLeft,  (SHORT) Rectangle.yBottom,
  2787.       (SHORT) (Rectangle.xRight-Rectangle.xLeft),
  2788.       (SHORT) (Rectangle.yTop-Rectangle.yBottom),
  2789.       SWP_SIZE | SWP_MOVE |
  2790.       ( OldPosition.fl & SWP_MAXIMIZE ) ) ;
  2791.   }
  2792.  
  2793.  /***************************************************************************
  2794.   * Reveal the window to the curious world.                                 *
  2795.   ***************************************************************************/
  2796.  
  2797.   WinShowWindow ( FrameWindow, TRUE ) ;
  2798. }
  2799.  
  2800. /****************************************************************************
  2801.  *                                                                          *
  2802.  *    Monitor Loop Thread                                                   *
  2803.  *                                                                          *
  2804.  ****************************************************************************/
  2805.  
  2806. static void _Optlink MonitorThread ( PVOID Parameter )
  2807. {
  2808.  /***************************************************************************
  2809.   * Get the parameter block pointer.                                        *
  2810.   ***************************************************************************/
  2811.  
  2812.   PMONITOR_PARMS Parms = PMONITOR_PARMS ( Parameter ) ;
  2813.  
  2814.  /***************************************************************************
  2815.   * Set this thread's priority as high as it can go.                        *
  2816.   ***************************************************************************/
  2817.  
  2818.   DosSetPrty ( PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, 0 ) ;
  2819.  
  2820.  /***************************************************************************
  2821.   * Start up the high resolution timer, if it is available.                 *
  2822.   ***************************************************************************/
  2823.  
  2824.   BOOL HiResTimer = OpenTimer ( ) ;
  2825.  
  2826.  /***************************************************************************
  2827.   * Loop until commanded to stop.                                           *
  2828.   ***************************************************************************/
  2829.  
  2830.   while ( Parms->Active )
  2831.   {
  2832.  
  2833.    /*************************************************************************
  2834.     * Reset the last time and count seen.                                   *
  2835.     *************************************************************************/
  2836.  
  2837.     ULONG LastMilliseconds ;
  2838.     TIMESTAMP Time [2] ;
  2839.  
  2840.     if ( HiResTimer )
  2841.       GetTime ( &Time[0] ) ;
  2842.     else
  2843.       DosQuerySysInfo ( QSV_MS_COUNT, QSV_MS_COUNT, &LastMilliseconds, sizeof(LastMilliseconds) ) ;
  2844.  
  2845.     ULONG LastCounter = *Parms->Counter ;
  2846.  
  2847.    /*************************************************************************
  2848.     * Sleep for a bit.                                                      *
  2849.     *************************************************************************/
  2850.  
  2851.     DosSleep ( 1000 ) ;
  2852.  
  2853.    /*************************************************************************
  2854.     * Find out how much time and counts went by.                            *
  2855.     *************************************************************************/
  2856.  
  2857.     ULONG CurrentCounter = *Parms->Counter ;
  2858.  
  2859.     ULONG DeltaMilliseconds ;
  2860.  
  2861.     if ( HiResTimer )
  2862.     {
  2863.       GetTime ( &Time[1] ) ;
  2864.  
  2865.       ULONG Nanoseconds ;
  2866.       DeltaMilliseconds = ComputeElapsedTime ( &Time[0], &Time[1], &Nanoseconds ) ;
  2867.  
  2868.       if ( Nanoseconds >= 500000L )
  2869.         DeltaMilliseconds ++ ;
  2870.     }
  2871.     else
  2872.     {
  2873.       ULONG Milliseconds ;
  2874.       DosQuerySysInfo ( QSV_MS_COUNT, QSV_MS_COUNT, &Milliseconds, sizeof(Milliseconds) ) ;
  2875.       DeltaMilliseconds = Milliseconds - LastMilliseconds ;
  2876.     }
  2877.  
  2878.    /*************************************************************************
  2879.     * Find out how much idle time was counted.  Adjust it to persecond.     *
  2880.     *************************************************************************/
  2881.  
  2882.     ULONG Counter = (ULONG) ( ( (double)(CurrentCounter-LastCounter) * 1000L ) / (double)DeltaMilliseconds ) ;
  2883.  
  2884.    /*************************************************************************
  2885.     * Tell the owner window to refresh its statistics.                      *
  2886.     *************************************************************************/
  2887.  
  2888.     WinPostMsg ( Parms->Owner, WM_REFRESH, MPFROMLONG(Counter), 0L ) ;
  2889.   }
  2890. }
  2891.  
  2892. /****************************************************************************
  2893.  *                                                                          *
  2894.  *                       Calibrate the Load Meter                           *
  2895.  *                                                                          *
  2896.  ****************************************************************************/
  2897.  
  2898. static ULONG CalibrateLoadMeter ( void )
  2899. {
  2900.  /***************************************************************************
  2901.   * Set result to zero as a default.                                        *
  2902.   ***************************************************************************/
  2903.  
  2904.   double AdjustedMaxLoad = 0.0 ;
  2905.  
  2906.  /***************************************************************************
  2907.   * If HRTIMER.SYS has been installed . . .                                 *
  2908.   ***************************************************************************/
  2909.  
  2910.   if ( OpenTimer ( ) )
  2911.   {
  2912.    /*************************************************************************
  2913.     * Increase this thread's priority to the maximum.                       *
  2914.     *************************************************************************/
  2915.  
  2916.     DosSetPrty ( PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM, 0 ) ;
  2917.  
  2918.    /*************************************************************************
  2919.     * Create the calibration thread and set its priority next highest.      *
  2920.     *************************************************************************/
  2921.  
  2922.     COUNTER_PARMS Parms ;
  2923.     ULONG MaxLoad ;
  2924.     Parms.Active = TRUE ;
  2925.     Parms.Counter = &MaxLoad ;
  2926.     TID tidCalibrate = _beginthread ( CounterThread, NULL, 0x3000, &Parms ) ;
  2927.     DosSetPrty ( PRTYS_THREAD, PRTYC_TIMECRITICAL, PRTYD_MAXIMUM-1, tidCalibrate ) ;
  2928.     DosSuspendThread ( tidCalibrate ) ;
  2929.  
  2930.    /*************************************************************************
  2931.     * Reset the calibration count, get the time, and let the counter go.    *
  2932.     *************************************************************************/
  2933.  
  2934.     MaxLoad = 0 ;
  2935.     TIMESTAMP Time[2] ;
  2936.     GetTime ( &Time[0] ) ;
  2937.     DosResumeThread ( tidCalibrate ) ;
  2938.  
  2939.    /*************************************************************************
  2940.     * Sleep for one second.                                                 *
  2941.     *************************************************************************/
  2942.  
  2943.     DosSleep ( 1000 ) ;
  2944.  
  2945.    /*************************************************************************
  2946.     * Suspend the calibration counter and get the time.                     *
  2947.     *************************************************************************/
  2948.  
  2949.     Parms.Active = FALSE ;
  2950.     GetTime ( &Time[1] ) ;
  2951.     DosWaitThread ( &tidCalibrate, DCWW_WAIT ) ;
  2952.  
  2953.    /*************************************************************************
  2954.     * Return priorities to normal.                                          *
  2955.     *************************************************************************/
  2956.  
  2957.     DosSetPrty ( PRTYS_THREAD, PRTYC_REGULAR, 0, 0 ) ;
  2958.  
  2959.    /*************************************************************************
  2960.     * Get the elapsed time and adjust the calibration count.                *
  2961.     *************************************************************************/
  2962.  
  2963.     ULONG Milliseconds ;
  2964.     ULONG Nanoseconds ;
  2965.     Milliseconds = ComputeElapsedTime ( &Time[0], &Time[1], &Nanoseconds ) ;
  2966.  
  2967.     AdjustedMaxLoad = (double)MaxLoad * 1.0E9 ;
  2968.     AdjustedMaxLoad /= (double)Milliseconds*1.0E6L + (double)Nanoseconds ;
  2969.  
  2970.    /*************************************************************************
  2971.     * Close down the connection to HRTIMER.SYS.                             *
  2972.     *************************************************************************/
  2973.  
  2974.     CloseTimer ( ) ;
  2975.   }
  2976.  
  2977.  /***************************************************************************
  2978.   * Return the adjusted calibration count.  If HRTIMER was not there, it    *
  2979.   *   will be zero.                                                         *
  2980.   ***************************************************************************/
  2981.  
  2982.   return ( (ULONG)AdjustedMaxLoad ) ;
  2983. }
  2984.  
  2985. /****************************************************************************
  2986.  *                                                                          *
  2987.  *                    General Purpose Counter Thread                        *
  2988.  *                                                                          *
  2989.  ****************************************************************************/
  2990.  
  2991. static void _Optlink CounterThread ( PVOID Parameter )
  2992. {
  2993.   PCOUNTER_PARMS Parms = PCOUNTER_PARMS ( Parameter ) ;
  2994.  
  2995.   while ( Parms->Active )
  2996.   {
  2997.     (*Parms->Counter) ++ ;
  2998.   }
  2999. }
  3000.